前提・実現したいこと
OpenCVのHSVカラーで色変化を手動で操作しようとしているのですが、
H,S,Vは各8ビットで、
H=0<ー>180
S=0<ー>255
V=0<ー>255
の範囲ですが、
SV色空間は底辺V、高さSの正方形の空間ではないようです。
この範囲で変化させていくと、白い色がピンク色になったりします。
底辺V高さSの三角形内でないといろは破綻するみたいです。
OpenCVでは
https://www.oh-benri-tools.com/tools/color/hsl-hsv-color-picker
の正方形のSV空間ではなく、
https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:Hsv_sample.png
この図のよう三角形のSV空間が正しいのでしょうかね?
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
「質問への追記・修正の依頼」に書いた
(R,G,B)の全パータンについて,
OpenCVの用いている変換式でHSVに変換してみて,
その結果のSVの分布を見ればわかるのではないでしょうか.
をやってみました.
- 1x1 の画像を作って,forループで色を変えては cv::cvtColor でHSVに変換させ,結果のSとVをプロットした.
- せっかくなので,BGR→HSV→BGR と再変換したらどの程度の誤差が生じるのかも調べてみた.
C++
1int main() 2{ 3 cv::Mat BGR( 1,1, CV_8UC3 ); 4 cv::Mat HSV( 1,1, CV_8UC3 ); 5 cv::Mat Result = cv::Mat::zeros( 256,256, CV_8U ); 6 unsigned int Diffs[ 10 ] = { 0 }; 7 8 for( int r=0; r<=255; ++r ) 9 { 10 for( int g=0; g<=255; ++g ) 11 { 12 for( int b=0; b<=255; ++b ) 13 { 14 BGR = cv::Scalar(b,g,r); 15 cv::cvtColor( BGR, HSV, cv::COLOR_BGR2HSV ); 16 const auto &hsv = HSV.at< cv::Vec3b >( 0,0 ); 17 Result.at< unsigned char >( hsv[1], hsv[2] ) = 255; 18 19 //逆変換 20 cv::cvtColor( HSV, BGR, cv::COLOR_HSV2BGR ); 21 const auto &bgr = BGR.at< cv::Vec3b >( 0,0 ); 22 int diff = std::min( abs( b-bgr[0] ) + abs( g-bgr[1] ) + abs( r-bgr[2] ), 9 ); 23 ++Diffs[diff]; 24 } 25 } 26 } 27 28 for( int i=0; i<10; ++i ) 29 { 30 std::cout << i << " : " << Diffs[i] << std::endl; 31 } 32 33 cv::imshow( "Result", Result ); 34 if( cv::waitKey() == 's' )cv::imwrite( "Result.png", Result ); 35 36 return 0; 37}
以下に,結果のスクリーンショットを示す.
左側の数値の表示は,再変換後の誤差(「市街地距離」というのかな)の度数分布.
正方形のが画像は 256x256 のS-V 空間に結果をプロットしたやつ(横軸がV,縦軸がS.黒地に白でプロットした).
- とりあえず S-V 空間全域にわたって相応に点が散らばっている.
- 再変換後の誤差の最大値は5であった.
(つまり,少なくとも白でプロットした位置については「それなりに真っ当に」BGRに変換できる(=急に突拍子もない色になったりはしない).
…という感じ.
以上より,
三角形内でないといろは破綻する
という感はない.
(「正方形」と言えるのでは?)
投稿2021/10/05 10:31
総合スコア11996
0
RGBからHSVへの変換では大丈夫ですが、HSVデータ内で操作するとやはり三角みたいですが、どうでしょう。テストでKey’1’押下でS(彩度)を全部100とすると崩れます。以外はV(明度)の半分の値をSに入れてみました。
int main()
{
cv::Mat img = cv::imread("test_HSV.jpg");
cv::Mat hsv; cv::Mat img2; cv::imshow("Test img", img); int key = cv::waitKey(); cv::cvtColor(img, hsv, cv::COLOR_BGR2HSV); for (int y = 0; y < hsv.rows; y++) { for (int x = 0; x < hsv.cols; x++) { cv::Vec3b p = hsv.at<cv::Vec3b>(cv::Point(x, y)); if (key == '1') { p[1] = 100; // S } else { if (p[2] < 128) { // v 0<->128<->255 p[1] = p[2] / 2; // S } else { p[1] = (255 - p[2]) / 2; // S } } hsv.at<cv::Vec3b>(cv::Point(x, y)) = p; } } cv::cvtColor(hsv, img2, cv::COLOR_HSV2BGR); cv::imshow("Test img 2", img2); cv::waitKey(10000); return 0;
投稿2021/10/05 13:06
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2021/10/05 14:33 編集
退会済みユーザー
2021/10/05 14:35 編集
2021/10/05 23:42 編集
2021/10/06 01:12
2021/10/06 01:15
2021/10/06 05:16
2021/10/06 06:49
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。