簡體   English   中英

高級 rgb2hsv 轉換 Matlab 到 opnecv/C++ 訪問像素值

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM