2017-10-26 7 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)に対して既に反復している場合、 'for(int j = 0; j api55

+0

@ api55実際には「i」は行(ステップi + = lab_img.cols * 3)に、ステップ「j」は列(j + = 3)にステップインします。だから、ループは正しいようです。もちろん、あなたのヒントはコードを改善する上では間違いありません。ありがとう –

+0

本当に、私は混乱した。私は間違いを今見ていない、私はそれとSEを実行しようとします。私にとっては、結果はすべての数字が最初は陽性(赤を除く)であるが、opencvのコンベンションへの変換はOKと思われます。確信していませんなぜ – api55

答えて

1

アルゴリズムを確認した後、アルゴリズムが正しく100%であり、問​​題は色空間であることに気付きました....木から緑色のように「間違って」変わった色を取りましょう。

GIMPのカラーピッカーツールを使用すると、使用されている緑色の少なくとも1つが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とCV ::マット機能を使用しています。

あなたはこの方法でも優れているインデックス

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

私が使用するのが好ましい主な理由** Lab * *色空間は[色差](https://en.wikipedia.org/wiki/Color_difference)Wikiに記述されていますが、一言で言えば、** RGB **距離は「知覚的に一様」ではありません。この記事ではLab **の色空間を使用するように提案されていますが、私は単純に** CIE76 ** DeltaEを使用します。しかし、あなたの提案を試してみましょう。 –

+0

はい、** RGB **はこの違いを見つけるのに悪いです。しかし、私は、人間がそれをどのように認識し、2.3未満は人間には目立っていないと述べているが、ライトグリーンとダークグリーンは緑色であることに興味があります。ラボではそれはもっと似ていますが、ダークブルーは知覚的に濃い緑色に似ています。そしてそれは間違った答えを与えます(少なくとも私はそれを見ている方法です)。しかし、あなたは色の量子化をしたいので、似ている色を見つけることが必要です – api55

関連する問題