img=imread('lena.jpg');
img2=rgb2hsv(img);
figure;
imshow(img);
figure;
imshow(img2);
imwrite(img2, 'lena_hsv.jpg');
fig.1 lena (format: RGB)
fig.2 lena (format: HSV) using MATLAB
fig3. lena (format: HSV) using OpenCV2.4.6
fig4. RGB(format: RGB)
fig.5 RGB (format HSV) using MATLAB
fig6. RGB (format: HSV) using OpenCV2.4.6
資料來源: HSL和HSV色彩空間
HSV 模型通常用於計算機圖形應用中。在用戶必須選擇一個顏色應用於特定圖形元素各種應用環境中,經常使用 HSV 色輪。在其中,色相(Hue)表示為圓環;可以使用一個獨立的三角形來表示飽和度(Saturation)和明度(Value)。典型的,這個三角形的垂直軸指示飽和度,而水平軸表示明度。在這種方式下,選擇顏色可以首先在圓環中選擇色相,在從三角形中選擇想要的飽和度和明度。
HSV 模型的另一種可視方法是圓錐體。在這種表示中,色相被表示為繞圓錐中心軸的角度,飽和度(Saturaion)被表示為從圓錐的橫截面的圓心到這個點的距離,明度(Value)被表示為從圓錐 的橫截面的圓心到頂點的距離。某些表示使用了六稜錐體。這種方法更適合在一個單一物體中展示這個 HSV 色彩空間;但是由於它的三維本質,它不適合在二維計算機界面中選擇顏色。
HSV 色彩空間還可以表示為類似於上述圓錐體的圓柱體,色相沿著圓柱體的外圓周變化,飽和度沿著從橫截面的圓心的距離變化,明度沿著橫截面到底面和頂面的距離而 變化。這種表示可能被認為是 HSV 色彩空間的更精確的數學模型;但是在實際中可區分出的飽和度和色相的級別數目隨著明度接近黑色而減少。此外計算機典型的用有限精度範圍來存儲 RGB 值;這約束了精度,再加上人類顏色感知的限制,使圓錐體表示在多數情況下更實用。
資料來源:RGB-to-HSV Color Conversion
-------------------------------------------------------------------------------------------------------------------------------------
開啟專案中mainwindow.ui, 加入<彩色空間轉換>, 加入<RGB2HSV>, 加入<影像1>
點選下方的<動作編輯器>, 點選<actionRGB2HSV1>, 按下滑鼠右鍵<跳到信號槽>
選擇<triggered()>動作事件
void MainWindow::on_actionRGB2HSV1_triggered()
{
actionRGB2HSV(0);//影像1RGB2HSV
}
-------------------------------------------------------------------------------------------------------
在mainwindow.h 新增一個成員變數
cv::Mat3b img_hsv; //HSV影像
在mainwindow.h 新增一個動作
void actionRGB2HSV(int index);//RGB2HSV
在mainwindow.cpp 撰寫對應的實作
// RGB2HSV
void MainWindow::actionRGB2HSV(int index)
{
double tic,toc,tcost; // 計時開始, 計時結束, 花費時間
tic = static_cast<double>(cv::getTickCount()); // tic
if( index==0 )
{
if(img_rgb1.empty()) return;
//img_rgb1.copyTo(img_hsv);
img_hsv.create(img_rgb1.rows, img_rgb1.cols);
cv::cvtColor(img_rgb1, img_hsv, CV_BGR2HSV); // 影像1進行RGB2HSV
}else{
if(img_rgb2.empty()) return;
img_hsv.create(img_rgb2.rows, img_rgb2.cols);
cv::cvtColor(img_rgb2, img_hsv, CV_BGR2HSV); // 影像2進行RGB2HSV
}
toc = static_cast<double>(cv::getTickCount()); // toc
tcost = (toc - tic)/cv::getTickFrequency();
QImage qimg_gray = me::Mat2QImage(img_hsv); // Mat 轉換至 QImage
// cv::namedWindow("HSV Image"); // define the window
// cv::imshow("HSV Image", img_hsv); // show the image
//cvWaitKey(0);
if(index==0)
{
me::imshow(ui->label, qimg_gray, 0); // 顯示影像1
}else{
me::imshow(ui->label_12, qimg_gray, 0); // 顯示影像2
}
}
---------------------------------------------------------------------------------------------------------
RGB to HSV conversion formula
---------------------------------------------------------------------------------------------------------
附帶一提: 從原始碼得知(OpenCV2.4.6\opencv\modules\imageproc\src\color.cpp)
OpenCV2.4.6提供兩種影像格式for RGB2HSV: 一個是uchar, 另一個是floating
struct RGB2HSV_b
{
typedef uchar channel_type;
RGB2HSV_b(int _srccn, int _blueIdx, int _hrange)
: srccn(_srccn), blueIdx(_blueIdx), hrange(_hrange)
{
CV_Assert( hrange == 180 || hrange == 256 );
}
void operator()(const uchar* src, uchar* dst, int n) const
{
int i, bidx = blueIdx, scn = srccn;
const int hsv_shift = 12;
static int sdiv_table[256];
static int hdiv_table180[256];
static int hdiv_table256[256];
static volatile bool initialized = false;
int hr = hrange;
const int* hdiv_table = hr == 180 ? hdiv_table180 : hdiv_table256;
n *= 3;
if( !initialized )
{
sdiv_table[0] = hdiv_table180[0] = hdiv_table256[0] = 0;
for( i = 1; i < 256; i++ )
{
sdiv_table[i] = saturate_cast<int>((255 << hsv_shift)/(1.*i));
hdiv_table180[i] = saturate_cast<int>((180 << hsv_shift)/(6.*i));
hdiv_table256[i] = saturate_cast<int>((256 << hsv_shift)/(6.*i));
}
initialized = true;
}
for( i = 0; i < n; i += 3, src += scn )
{
int b = src[bidx], g = src[1], r = src[bidx^2];
int h, s, v = b;
int vmin = b, diff;
int vr, vg;
CV_CALC_MAX_8U( v, g );
CV_CALC_MAX_8U( v, r );
CV_CALC_MIN_8U( vmin, g );
CV_CALC_MIN_8U( vmin, r );
diff = v - vmin;
vr = v == r ? -1 : 0;
vg = v == g ? -1 : 0;
s = (diff * sdiv_table[v] + (1 << (hsv_shift-1))) >> hsv_shift;
h = (vr & (g - b)) +
(~vr & ((vg & (b - r + 2 * diff)) + ((~vg) & (r - g + 4 * diff))));
h = (h * hdiv_table[diff] + (1 << (hsv_shift-1))) >> hsv_shift;
h += h < 0 ? hr : 0;
dst[i] = saturate_cast<uchar>(h);
dst[i+1] = (uchar)s;
dst[i+2] = (uchar)v;
}
}
int srccn, blueIdx, hrange;
};
------------------------------------------------------------------------------------------------------------------------
struct RGB2HSV_f
{
typedef float channel_type;
RGB2HSV_f(int _srccn, int _blueIdx, float _hrange)
: srccn(_srccn), blueIdx(_blueIdx), hrange(_hrange) {}
void operator()(const float* src, float* dst, int n) const
{
int i, bidx = blueIdx, scn = srccn;
float hscale = hrange*(1.f/360.f);
n *= 3;
for( i = 0; i < n; i += 3, src += scn )
{
float b = src[bidx], g = src[1], r = src[bidx^2];
float h, s, v;
float vmin, diff;
v = vmin = r;
if( v < g ) v = g;
if( v < b ) v = b;
if( vmin > g ) vmin = g;
if( vmin > b ) vmin = b;
diff = v - vmin;
s = diff/(float)(fabs(v) + FLT_EPSILON);
diff = (float)(60./(diff + FLT_EPSILON));
if( v == r )
h = (g - b)*diff;
else if( v == g )
h = (b - r)*diff + 120.f;
else
h = (r - g)*diff + 240.f;
if( h < 0 ) h += 360.f;
dst[i] = h*hscale;
dst[i+1] = s;
dst[i+2] = v;
}
}
int srccn, blueIdx;
float hrange;
};
原始程式碼(source code): RGB2HSVQt5OpenCV246
------------------------------------------------------------------------------------------------------------------------
操作測試:
留言列表