計画
私のプロジェクトは、ターゲット ウィンドウのビットマップをキャプチャして に変換し、IplImage
そのイメージを に表示してcvNamedWindow
、さらに処理を行うことができます。
テストのために、次のようにイメージを MSPaint にロードしました。
ユーザーは、イメージ内の任意の数のピクセル上でマウスをクリック アンド ドラッグして、vector<cv::Scalar_<BYTE>>
これらの RGB カラー値を含む を作成できます。
次に、 の助けを借りてColorRGBToHLS()
、この配列は次のように色相によって左から右にソートされます。
// PixelColor is just a cv::Scalar_<BYTE>
bool comparePixelColors( PixelColor& pc1, PixelColor& pc2 ) {
WORD h1 = 0, h2 = 0;
WORD s1 = 0, s2 = 0;
WORD l1 = 0, l2 = 0;
ColorRGBToHLS(RGB(pc1.val[2], pc1.val[1], pc1.val[0]), &h1, &l1, &s1);
ColorRGBToHLS(RGB(pc2.val[2], pc2.val[1], pc2.val[0]), &h2, &l2, &s2);
return ( h1 < h2 );
}
//..(elsewhere in code)
std::sort(m_colorRange.begin(), m_colorRange.end(), comparePixelColors);
...そして、次のような新しいcvNamedWindow
に表示されます。
問題
ここでのアイデアは、この選択された色の範囲が白になり、ソース画像の残りが黒になるバイナリしきい値画像(または「マスク」)を作成することです... 「色で選択」ツールの方法と同様GIMP で動作するか、「魔法の杖」ツールが Photoshop で動作します... ただし、特定の輪郭のある選択に限定するのではなく、文字通り画像全体を操作しています。
を読みましたがcvInRangeS
、まさに私が必要としているもののようです。
ただし、何らかの理由で、しきい値処理された画像は常に完全に黒くなります...
VOID ShowThreshedImage(const IplImage* src, const PixelColor& min, const PixelColor& max)
{
IplImage* imgHSV = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 3);
cvCvtColor(src, imgHSV, CV_RGB2HLS);
cvNamedWindow("T1");
cvShowImage("T1", imgHSV); // <-- Shows up like the image below
IplImage* imgThreshed = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
cvInRangeS(imgHSV, min, max, imgThreshed);
cvNamedWindow("T2");
cvShowImage("T2", imgThreshed); // <-- SHOWS UP PITCH BLACK!
}
これは、"T1"
ウィンドウが最終的にどのように見えるかです (これは正しいと思いますか?) :
色範囲ベクトルは RGB として格納されるため(そして OpenCV は内部的にこの順序を BGR に逆にするため)、最小値/最大値を HLS に変換してから次のように渡しますShowThreshedImage()
。
CvScalar rgbPixelToHSV(const PixelColor& pixelColor)
{
WORD h = 0, s = 0, l = 0;
ColorRGBToHLS(RGB(pixelColor.val[2], pixelColor.val[1], pixelColor.val[0]), &h, &l, &s);
return PixelColor(h, s, l);
}
//...(elsewhere in code)
if(m_colorRange.size() > 0)
m_minHSV = rgbPixelToHSV(m_colorRange[0]);
if(m_colorRange.size() > 1)
m_maxHSV = rgbPixelToHSV(m_colorRange[m_colorRange.size() - 1]);
ShowThreshedImage(m_imgSrc, m_minHSV, m_maxHSV);
...しかし、この変換を行わず、代わりに RGB 値を渡すだけでも、結果は完全に黒い画像になります。特定の最小値/最大値を手動で差し込むことさえ試みましたが、得られた最良の結果は、いくつかの点灯したピクセルでした (ただし、間違ったものです)。
質問:
ここで何が間違っていますか?メソッド
についてわからないことはありますか?cvInRangeS
ソース画像から選択した範囲を適切にしきい値処理するために、すべての色をステップスルーする必要がありますか?
これを達成する他の方法はありますか?
お時間をいただきありがとうございます。
アップデート:
がのすべての値をの値よりも低くすることをcvInRangeS
期待していることを発見しました。しかし、色の範囲が選択されている場合、これが当てはまるという保証はないようで、多くの場合、黒のしきい値の画像になります。また、値を交換してこのルールを適用すると、新しい範囲内に不要な色が含まれる可能性があります (場合によっては、必要な色だけでなくすべての色が含まれる可能性があります)。min
max
したがって、ここでの本当の質問は、
「RGB カラーの配列をどのようにセグメント化し、それらを使用して画像のしきい値を設定するのですか?」ということになると思います。