我正在构建一个目标C / C ++和openCV的程序。我对Objective C非常熟练,但对C ++很陌生
我正在构建自定义RGB2HSV算法。我的算法与openCV库cvtColor(in,out,CV_RGB2HSV)略有不同。
我尝试将Matlab转换为opencV / C ++的那个产生如此清晰的HSV图像,在进一步处理之前不需要额外的过滤。下面的代码 - Matlab代码是不言自明的。
我尝试将其转换为C ++ / openCV函数,但我试图访问图像的像素值。我是C ++的新手。 我读了很多关于如何访问Mat结构的内容,但通常我会在零的位置获得一串字母或者通常是这样的“\ 202 k g”。当我尝试对say \ 202进行任何乘法运算时,结果与数学无关。
请帮我正确访问像素值。同样在当前版本中使用uchar将无法工作,因为某些值超出0-255范围。 算法不是我的。我甚至无法指出来源,但它显示出比RGB2HSV更好的结果。
下面的算法也适用于一个像素。它需要应用于图像中的每个像素,因此在最终版本中,它需要用{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
答案 0 :(得分:1)
要访问3通道,8位精度图像(类型CV_8UC3
)中像素的值,您必须这样做:
cv::Mat image;
cv::Vec3b BGR = image.at<cv::Vec3b>(i,j);
如果如你所说,8位精度和范围不够,你可以声明cv::Mat
类型为CV_32F
来存储浮点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 docs以了解详情。
答案 1 :(得分:0)
如果您担心性能并且对像素索引非常熟悉,则可以直接使用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访问更容易读/错。
参考文献:
答案 2 :(得分:0)
感谢大家的帮助。 感谢您的提示,我构建了自定义rgb2hsv函数C ++ / openCV。
分别从左上角开始,bgr-> gray-&gt;边缘之后的边缘,bgr-> HSV->边缘,bgr-> customHSV->边缘 在它们下面的每个对应的过滤器设置中实现大致相同的清晰结果。过滤器的半径越大,计算越复杂和耗时。
它在图像处理的后续步骤中产生更清晰的边缘。 它可以进一步调整r g b通道中的参数进行调试:
red =(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;
}