[英]Advanced rgb2hsv conversion Matlab to opnecv/C++ access to pixel value
我正在用目標 C/C++ 和 openCV 構建一個程序。 我對 Objective C 非常熟練,但對 C++ 不熟悉。
我正在構建自定義 RGB2HSV 算法。 我的算法與 openCV 庫 cvtColor(in, out, CV_RGB2HSV) 略有不同。
我嘗試將 Matlab 轉換為 opencV/C++ 的那個生成了如此清晰的 HSV 圖像,因此在進一步處理之前不需要額外的過濾。 下面的代碼 - Matlab 代碼是不言自明的。
我嘗試將其轉換為 C++/openCV 函數,但我在嘗試訪問圖像的像素值時遇到了困難。 我是 C++ 的新手。 我閱讀了很多關於如何訪問 Mat 結構的方法,但通常我會在零的位置獲得一堆字母或一個通常類似於“\\202 kg”的數字。 當我嘗試對 \\202 進行任何乘法運算時,結果與數學無關。
請幫助我正確訪問像素值。 同樣在當前版本中使用 uchar 將不起作用,因為某些值超出了 0-255 范圍。 算法不是我的。 我什至無法指出來源,但它的結果明顯優於庫存 RGB2HSV。
下面的算法也是針對一個像素的。 它需要應用於圖像中的每個像素,因此在最終版本中它需要使用 for { for {}} 循環進行包裝。
我也希望與社區分享此方法,以便每個人都可以從中受益並節省預過濾。
請幫我把它翻譯成 C++/openCV。 如果可能的話,最好采用速度明智的做法。 或者至少如何清楚地訪問像素值,以便它適用於一系列數學方程。 提前致謝。
function[H, S, V] = rgb2hsvPixel(R,G,B)
% Algorithm:
% In case of 8-bit and 16-bit images, `R`, `G`, and `B` are converted to the
% floating-point format and scaled to fit the 0 to 1 range.
%
% V = max(R,G,B)
% S = / (V - min(R,G,B)) / V if V != 0
% \ 0 otherwise
% / 60*(G-B) / (V - min(R,G,B)) if V=R
% H = | 120 + 60*(B-R) / (V - min(R,G,B)) if V=G
% \ 240 + 60*(R-G) / (V - min(R,G,B)) if V=B
%
% If `H<0` then `H=H+360`. On output `0<=V<=1`, `0<=S<=1`, `0<=H<=360`.
red = (double(R)-16)*255/224; % \
green = (double(G)-16)*255/224; % }- R,G,B (0 <-> 255) -> (-18.2143 <-> 272.0759)
blue = (min(double(B)*2,240)-16)*255/224; % /
minV = min(red,min(green,blue));
value = max(red,max(green,blue));
delta = value - minV;
if(value~=0)
sat = (delta*255) / value;% s
if (delta ~= 0)
if( red == value )
hue = 60*( green - blue ) / delta; % between yellow & magenta
elseif( green == value )
hue = 120 + 60*( blue - red ) / delta; % between cyan & yellow
else
hue = 240 + 60*( red - green ) / delta; % between magenta & cyan
end
if( hue < 0 )
hue = hue + 360;
end
else
hue = 0;
sat = 0;
end
else
% r = g = b = 0
sat = 0;
hue = 0;
end
H = max(min(floor(((hue*255)/360)),255),0);
S = max(min(floor(sat),255),0);
V = max(min(floor(value),255),0);
end
要訪問 3 通道、8 位精度圖像(類型CV_8UC3
)中像素的值,您必須這樣做:
cv::Mat image;
cv::Vec3b BGR = image.at<cv::Vec3b>(i,j);
如果,如您所說,8 位精度和范圍不夠,您可以聲明一個CV_32F
類型的cv::Mat
來存儲浮點 32 位數字。
cv::Mat image(height, width, CV_32FC3);
//fill your image with data
for(int i = 0; i < image.rows; i++) {
for(int j = 0; j < image.cols; j++) {
cv::Vec3f BGR = image.at<cv::Vec3f>(i,j)
//process your pixel
cv::Vec3f HSV; //your calculated HSV values
image.at<cv::Vec3f>(i,j) = HSV;
}
}
請注意,OpenCV 以 BGR 順序而不是 RGB 存儲 rgb 值。 查看OpenCV 文檔以了解更多信息。
如果您關心性能並且對像素索引相當滿意,則可以直接使用Mat ptr 。
例如:
cv::Mat img = cv::Mat::zeros(4, 8, CV_8UC3);
uchar *ptr_row_img;
int cpt = 0;
for(int i = 0; i < img.rows; i++) {
ptr_row_img = img.ptr<uchar>(i);
for(int j = 0; j < img.cols; j++) {
for(int c = 0; c < img.channels(); c++, cpt++, ++ptr_row_img) {
*ptr_row_img = cpt;
}
}
}
std::cout << "img=\n" << img << std::endl;
前面的代碼應該打印:
img= [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 ; 24、25、26、27、28、29、30、31、32、33、34、35、36、37、38、39、40、41、42、43、44、45、46、47; 48、49、50、51、52、53、54、55、56、57、58、59、60、61、62、63、64、65、66、67、68、69、70、71; 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95]
在大多數情況下, at訪問應該足夠了,並且比使用 ptr 訪問更具可讀性/更不容易出錯。
參考:
謝謝大家的幫助。 感謝您的提示,我構建了自定義 rgb2hsv 函數 C++/openCV。
從左上角開始分別是bgr->gray->edges、bgr->HSV->edges、bgr->customHSV->edges之后的edges,在它們下面分別設置了相應的filters,以達到大致相同的清晰效果。 過濾器的半徑越大,計算就越復雜和耗時。
它在接下來的圖像處理步驟中產生更清晰的邊緣。 可以進一步調整 rgb 通道中的參數:
紅色 = (red-16)*1.1384; //255/244=1.1384 這里 16 – 數字越大,V 越清晰 255/244 – 也會影響將其擴展到 0-255 范圍以外的結果,稍后將被剪裁。 這里的數字似乎是黃金比例,但任何人都可以根據特定需求進行調整。
使用此功能,可以通過將顏色直接連接到原始圖像中的適當通道來避免將 BGR 轉換為 RGB。
可能這是一個有點笨拙的表現明智。 就我而言,它用於色彩平衡和直方圖調整的第一步,因此速度不是那么重要。
為了在持續處理視頻流中使用它需要速度優化,我認為通過使用指針和降低循環復雜度。 優化不完全是我的一杯茶。 因此,如果有人幫助為社區優化它,那就太好了。 這里就可以使用了:
Mat bgr2hsvCustom ( Mat& image )
{
//smallParam = 16;
for(int x = 0; x < image.rows; x++)
{
for(int y = 0; y<image.cols; y++)
{
//assigning vector to individual float BGR values
float blue = image.at<cv::Vec3b>(x,y)[0];
float green = image.at<cv::Vec3b>(x,y)[1];
float red = image.at<cv::Vec3b>(x,y)[2];
float sat, hue, minValue, maxValue, delta;
float const ang0 = 0; // func min and max don't accept varaible and number
float const ang240 = 240;
float const ang255 = 255;
red = (red-16)*1.1384; //255/244
green = (green-16)*1.1384;
blue = (min(blue*2,ang240)-16)*1.1384;
minValue = min(red,min(green,blue));
maxValue = max(red,max(green,blue));
delta = maxValue - minValue;
if (maxValue != 0)
{
sat = (delta*255) / maxValue;
if ( delta != 0)
{
if (red == maxValue){
hue = 60*(green - blue)/delta;
}
else if( green == maxValue ) {
hue = 120 + 60*( blue - red )/delta;
}
else{
hue = 240 + 60*( red - green )/delta;
}
if( hue < 0 ){
hue = hue + 360;
}
}
else{
sat = 0;
hue = 0;
}
}
else{
hue = 0;
sat = 0;
}
image.at<cv::Vec3b>(x,y)[0] = max(min(floor(maxValue),ang255),ang0); //V
image.at<cv::Vec3b>(x,y)[1] = max(min(floor(sat),ang255),ang0); //S
image.at<cv::Vec3b>(x,y)[2] = max(min(floor(((hue*255)/360)),ang255),ang0); //H
}
}
return image;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.