高级rgb2hsv转换Matlab到opnecv / C ++访问像素值

时间:2016-05-27 06:11:53

标签: c++ image algorithm matlab opencv

我正在构建一个目标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

3 个答案:

答案 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)

enter image description here感谢大家的帮助。 感谢您的提示,我构建了自定义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;
}