2017-10-26 3 views
0

나는 다음과 같은 기능을 사용하여 일부 미리 정의 된 색상에 내 이미지 색상을 줄이기 위해 노력하는 실험실 색상 양자화 :OpenCV의 : 사전 정의 된 색상

void quantize_img(cv::Mat &lab_img, std::vector<cv::Scalar> &lab_colors) { 
    float min_dist, dist; 
    int min_idx; 
    for (int i = 0; i < lab_img.rows*lab_img.cols * 3; i += lab_img.cols * 3) { 
     for (int j = 0; j < lab_img.cols * 3; j += 3) { 
      min_dist = FLT_MAX; 
      uchar &l = *(lab_img.data + i + j + 0); 
      uchar &a = *(lab_img.data + i + j + 1); 
      uchar &b = *(lab_img.data + i + j + 2); 
      for (int k = 0; k < lab_colors.size(); k++) { 
       double &lc = lab_colors[k](0); 
       double &ac = lab_colors[k](1); 
       double &bc = lab_colors[k](2); 
       dist = (l - lc)*(l - lc)+(a - ac)*(a - ac)+(b - bc)*(b - bc); 
       if (min_dist > dist) { 
        min_dist = dist; 
        min_idx = k; 
       } 
      } 
      l = lab_colors[min_idx](0); 
      a = lab_colors[min_idx](1); 
      b = lab_colors[min_idx](2); 
     } 
    } 
} 

것은 그러나 제대로 작동하지 않는 것! 예를 들어 다음 입력에 대한 출력은 놀라운 것처럼 보입니다!

if (!(src = imread("im0.png")).data) 
    return -1; 
cvtColor(src, lab, COLOR_BGR2Lab); 
std::vector<cv::Scalar> lab_color_plate_({ 
    Scalar(100, 0 , 0), //white 
    Scalar(50 , 0 , 0), //gray 
    Scalar(0 , 0 , 0), //black 
    Scalar(50 , 127, 127), //red 
    Scalar(50 ,-128, 127), //green 
    Scalar(50 , 127,-128), //violet 
    Scalar(50 ,-128,-128), //blue 
    Scalar(68 , 46 , 75), //orange 
    Scalar(100,-16 , 93) //yellow 
}); 
//convert from conventional Lab to OpenCV Lab 
for (int k = 0; k < lab_color_plate_.size(); k++) { 
    lab_color_plate_[k](0) *= 255.0/100.0; 
    lab_color_plate_[k](1) += 128; 
    lab_color_plate_[k](2) += 128; 
} 
quantize_img(lab, lab_color_plate_); 
cvtColor(lab, lab, CV_Lab2BGR); 
imwrite("im0_lab.png", lab); 

입력 이미지 : 어디에 문제가 Input image

출력 이미지 enter image description here

는 사람이 설명 할 수 있습니까?

+0

j가 필요한 경우 이미 모든 픽셀 (i 포함)에 대해 반복 작업을하는 경우'for (int j = 0; j api55

+0

@ api55 실제로 "i"는 행 (노트 i + = lab_img.cols * 3) 및 "j"단계 (col = j + 3)에 대해 단계를 밟습니다. 그래서 루프가 올바른 것처럼 보입니다. 물론 팁은 코드 개선에 유용합니다. 감사합니다 –

+0

사실, 나는 혼란스러워. 나는 어떤 실수도 지금 보지 않는다, 나는 그것을 달리게하려고 노력할 것이다. 나에게 결과는 모든 숫자가 처음에는 (붉은 색을 제외하고) 양수이지만, opencv 컨벤션으로의 전환은 괜찮아 보인다는 것을 알 수있다 .... 확실하지 않은 이유 – api55

답변

1

알고리즘을 확인한 후 알고리즘이 100 % 정확하고 문제가 색상 공간이라는 것을 알았습니다 .... 나무에서 녹색과 같이 "잘못 수정 된"색상 중 하나를 선택합시다.

김프에서 색상 선택 도구를 사용하면 사용 된 녹색 중 적어도 하나가 RGB (111, 139, 80)임을 알 수 있습니다. 이것을 LAB로 변환하면 (54.4, -20.7, 28.3)이됩니다. 녹색으로 거리는 (귀하의 수식으로) 21274.34이며, 회색으로 거리는 1248.74 ... 녹색이므로 녹색 위에 회색을 선택합니다.

LAB의 많은 값은 녹색 값을 생성 할 수 있습니다. 색상 범위를 this webpage에서 테스트 할 수 있습니다. HSV 또는 HSL을 사용하고 색조 인 H 값만 비교하는 것이 좋습니다. 다른 값은 녹색의 음색 만 변경하지만 색조의 작은 범위는 녹색이라는 것을 결정합니다. 이것은 아마 당신에게 더 정확한 결과를 줄 것입니다.

for (int i = 0; i < lab_img.rows; ++i) { 
    for (int j = 0; j < lab_img.cols; ++j) { 
     Vec3b pixel = lab_img.at<Vec3b>(i,j); 
    } 
} 

이 방법은 코드를 읽기이며, 일부 검사는 디버그 모드에서 수행됩니다

어떤 제안이 코드를 개선하기로

이 같은 Vec3b 및 이력서 :: 매트 기능을 사용합니다. 당신이 인덱스

auto currentData = reinterpret_cast<Vec3b*>(lab_img.data); 
for (size_t i = 0; i < lab_img.rows*lab_img.cols; i++) 
{ 
    auto& pixel = currentData[i]; 
} 

신경 쓰지 않기 때문에

다른 방법은이 방법은 또한 더 나은 하나 개의 루프를 수행하는 것입니다. 이 마지막 부분은 단지 제안 일 뿐이며 현재 코드에 아무런 문제가 없으며 외부 뷰어에게 이해하기가 더 쉽습니다.

+0

내가 선호하는 주된 이유 ** 실험실 * * 색상 공간은 [색상 차이] (https://en.wikipedia.org/wiki/Color_difference) Wiki에 설명되어 있지만, 간단히 말해서 ** RGB ** 거리는 "지각 적으로 균일합니다". 이 기사에서는 ** Lab ** 색상 공간을 사용하도록 제안했으며 단순히 ** CIE76 ** DeltaE 만 사용합니다.그러나, 당신의 제안을 시도하자. –

+0

네, ** RGB ** 차이점을 찾는 데 좋지 않습니다. 그러나 나는이 기사가 인간이 그것을 어떻게 감지하는지에 대해 이야기하고, 2.3 미만은 인간에게는 눈에 띄지 않는다고 생각하지만, 밝은 녹색과 진한 녹색은 녹색이라고 관심이있다. 실험실에서는 더 진한 청색이 짙은 녹색과 지각 적으로 유사하다. 그리고 나서 그것은 잘못된 대답을 준다 (적어도 그것이 내가 보는 방식이다). 그러나 원하는 것은 색의 양자화입니다. 비슷한 색을 찾아야합니다. – api55