【问题标题】:BGR to HSV and back againBGR 到 HSV 并再次返回
【发布时间】:2016-06-14 18:11:52
【问题描述】:

文档似乎没有解释 HSV->BGR 转换的预期输入范围。这是一些示例代码,我在将其转换为 HSV 后尝试取回原始 BGR 值。有谁知道预期的缩放比例?

#include <iostream>

#include <opencv2/opencv.hpp>

cv::Vec3b HSVtoBGR(const cv::Vec3f& hsv)
{
    cv::Vec3f hsvAdjusted = hsv; // If we use this directly, the output is (0,0,1) which is very wrong
    //hsvAdjusted[0] *= 360.; // If we do this to bring all of the values into the range (0,1), the output is (0,1,0), which is also very wrong

    // If we do this to bring all of the values into the range (0,255), the output is (0,0,200), which is still very wrong
    hsvAdjusted[1] *= 255./360.;
    hsvAdjusted[1] *= 255.;
    hsvAdjusted[2] *= 255.;

    cv::Mat_<cv::Vec3f> hsvMat(hsvAdjusted);

    cv::Mat_<cv::Vec3f> bgrMat;

    cv::cvtColor(hsvMat, bgrMat, CV_HSV2BGR);

    cv::Vec3b bgr = static_cast<cv::Vec3b>(bgrMat(0,0));
    return bgr;
}

/** Input 0 <= B <= 255, 0 <= G <= 255, 0 <= R <= 255
  * Output 0 <= H <= 360, 0 <= S <= 1, 0 <= V <= 1  */
cv::Vec3f BGRtoHSV(const cv::Vec3b& bgr)
{
    cv::Mat3f bgrMat(static_cast<cv::Vec3f>(bgr));

    bgrMat *= 1./255.;

    cv::Mat3f hsvMat;
    cv::cvtColor(bgrMat, hsvMat, CV_BGR2HSV);

    cv::Vec3f hsv = hsvMat(0,0);

    return hsv;
}

int main()
{
    // Create a BGR color
    cv::Vec3b bgr(5, 100, 200);
    std::cout << "bgr: " << bgr << std::endl;

    // Convert BGR to HSV
    cv::Vec3f hsv = BGRtoHSV(bgr);
    std::cout << "hsv: " << hsv << std::endl; // outputs // (29.23, .976, .7843), which seems correct

    // Convert back from HSV to BGR
    cv::Vec3b bgr2 = HSVtoBGR(hsv);
    std::cout << "bgr2: " << bgr2 << std::endl;

    return 0;
}

【问题讨论】:

    标签: c++ opencv opencv3.0


    【解决方案1】:

    您在函数HSVtoBGR 中存在一些缩放问题。

    您需要将转换后的结果乘以 255,而不是之前。请记住,类型为 CV_32FCV_8UMat 会发生不同的转换。

    这应该可以按预期工作:

    cv::Vec3b HSVtoBGR(const cv::Vec3f& hsv)
    {
        cv::Mat_<cv::Vec3f> hsvMat(hsv);
        cv::Mat_<cv::Vec3f> bgrMat;
    
        cv::cvtColor(hsvMat, bgrMat, CV_HSV2BGR);
    
        bgrMat *= 255; // Upscale after conversion
    
        // Conversion to Vec3b is handled by OpenCV, no need to static_cast
        return bgrMat(0);
    }
    

    【讨论】:

      【解决方案2】:

      单独运行下面的代码。您将能够控制 RGB 值并获得相应的 HSV 缩放比例。

      #include<iostream>
      #include<opencv2/core/core.hpp>
      #include<opencv2/imgproc/imgproc.hpp>
      #include<opencv2/highgui/highgui.hpp>
      
      using namespace std;
      using namespace cv;
      
      char RGB_window[30] = "RGB Window";
      char HSV_window[30] = "HSV Window";
       Mat src,hsv;
      
       static void onMouse( int event, int x, int y, int f, void* ){
       Mat image=src.clone();
       Vec3b rgb=image.at<Vec3b>(y,x);
       int B=rgb.val[0];
       int G=rgb.val[1];
       int R=rgb.val[2];
      
        Mat HSV;
        Mat RGB=image(Rect(x,y,1,1));//capture that pixel in its own ROI
        cvtColor(RGB, HSV,CV_BGR2HSV);
      
          Vec3b hsv=HSV.at<Vec3b>(0,0);
          int H=hsv.val[0];
          int S=hsv.val[1];
          int V=hsv.val[2];
      
          char name[30];
          sprintf(name,"B=%d",B);
          putText(image,name, Point(150,40) , FONT_HERSHEY_SIMPLEX, .7, Scalar(0,255,0), 2,8,false );
      
          sprintf(name,"G=%d",G);
          putText(image,name, Point(150,80) , FONT_HERSHEY_SIMPLEX, .7, Scalar(0,255,0), 2,8,false );
      
          sprintf(name,"R=%d",R);
          putText(image,name, Point(150,120) , FONT_HERSHEY_SIMPLEX, .7, Scalar(0,255,0), 2,8,false );
      
          sprintf(name,"H=%d",H);
          putText(image,name, Point(25,40) , FONT_HERSHEY_SIMPLEX, .7, Scalar(0,255,0), 2,8,false );
      
          sprintf(name,"S=%d",S);
          putText(image,name, Point(25,80) , FONT_HERSHEY_SIMPLEX, .7, Scalar(0,255,0), 2,8,false );
      
          sprintf(name,"V=%d",V);
          putText(image,name, Point(25,120) , FONT_HERSHEY_SIMPLEX, .7, Scalar(0,255,0), 2,8,false );
      
          sprintf(name,"X=%d",x);
          putText(image,name, Point(25,300) , FONT_HERSHEY_SIMPLEX, .7, Scalar(0,0,255), 2,8,false );
      
          sprintf(name,"Y=%d",y);
          putText(image,name, Point(25,340) , FONT_HERSHEY_SIMPLEX, .7, Scalar(0,0,255), 2,8,false );
          //namedWindow("Ref HSV",WINDOW_NORMAL);
          Mat ref(50,50,CV_8UC3,Scalar(H,S,V));
       //imwrite("hsv.jpg",image);
       imshow( RGB_window, image );
       //imshow( "Ref HSV",ref);
      
      }
      
      
      
      int main()
      
      {
      //VideoCapture cap(0);
      static int Bs=0,Gs=0,Rs=0;
      namedWindow("colourCtrl");
       //src = imread("bgr.png",1);
      for(;;)
      {
        //cap>>src;
        createTrackbar("B","colourCtrl",&Bs,255);
        createTrackbar("G","colourCtrl",&Gs,255);
        createTrackbar("R","colourCtrl",&Rs,255);
        Mat refRGB(500,500,CV_8UC3,Scalar(Bs,Gs,Rs));
        src=refRGB;
        cvtColor(src,hsv,CV_BGR2HSV);
        imshow(RGB_window,src);
       imshow(HSV_window,hsv);
       setMouseCallback( RGB_window, onMouse, 0 );
       setMouseCallback( HSV_window, onMouse, 0 );
       char c=waitKey(10);
       if(c=='b')
          {break;}
       }
      return 0;
      }
      

      【讨论】:

      • 这里的问题不是如何从 BGR 中获取 HSV,而是如何从 BGR 中获取 HSV 作为浮点值作为 uchar 值,然后返回。问题在于缩放,因为 uchar 和 float 值会发生不同的转换。
      • 在 HSV 像素中,24 位按 H、S、V 的顺序分配。 V 将是 (B,G,R) 的最大值,因此它将作为 uchar 返回。将 S uchar 值转换为浮点数并将其除以 255,将返回 S 浮点值。当B值为最大值时,H=30*V*([(R-G)]/[max(B,G,R)-min(B,G,R)] + 4)。
      • 实际上比这简单得多。看我的回答;D
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-21
      • 2011-02-20
      • 2011-06-11
      • 2011-08-05
      • 1970-01-01
      相关资源
      最近更新 更多