【问题标题】:Converting an OpenCV Image to Black and White将 OpenCV 图像转换为黑白图像
【发布时间】:2011-11-29 07:11:49
【问题描述】:

如何将灰度 OpenCV 图像转换为黑白图像?我看到 similar question 已被询问,但我使用的是 OpenCV 2.3,建议的解决方案似乎不再有效。

我正在尝试将灰度图像转换为黑白,以便任何不是绝对黑色的东西都是白色的,并将其用作surf.detect() 的蒙版,以忽略在黑色蒙版边缘发现的关键点地区。

下面的 Python 让我快到了,但发送到 Threshold() 的阈值似乎没有任何效果。如果我将其设置为 0 或 16 或 128 或 255,结果是相同的,所有值 > 128 的像素都变为白色,而其他所有像素都变为黑色。

我做错了什么?

import cv, cv2
fn = 'myfile.jpg'
im_gray = cv2.imread(fn, cv.CV_LOAD_IMAGE_GRAYSCALE)
im_gray_mat = cv.fromarray(im_gray)
im_bw = cv.CreateImage(cv.GetSize(im_gray_mat), cv.IPL_DEPTH_8U, 1);
im_bw_mat = cv.GetMat(im_bw)
threshold = 0 # 128#255# HAS NO EFFECT!?!?
cv.Threshold(im_gray_mat, im_bw_mat, threshold, 255, cv.CV_THRESH_BINARY | cv.CV_THRESH_OTSU);
cv2.imshow('', np.asarray(im_bw_mat))
cv2.waitKey()

【问题讨论】:

    标签: python image-processing opencv computer-vision


    【解决方案1】:

    使用新的 cv2 Python 绑定的步骤类似于您所指的答案:

    1.读取灰度图像

    import cv2
    im_gray = cv2.imread('grayscale_image.png', cv2.IMREAD_GRAYSCALE)
    

    2。将灰度图像转换为二进制

    (thresh, im_bw) = cv2.threshold(im_gray, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
    

    使用 Otsu 的方法从图像中自动确定阈值,或者如果您已经知道可以使用的阈值:

    thresh = 127
    im_bw = cv2.threshold(im_gray, thresh, 255, cv2.THRESH_BINARY)[1]
    

    3。保存到磁盘

    cv2.imwrite('bw_image.png', im_bw)
    

    【讨论】:

    • 注意:至少在 OpenCV 3.1(可能更早)中,cv2.CV_LOAD_IMAGE_GRAYSCALE 现在是cv2.IMREAD_GRAYSCALE。除此之外,该代码使用 Python 3.5 完美运行。
    • 这可能超出了问题的范围,但是如果自动选择了阈值,您能否解释一下 2 中第一个代码中的值 128 是什么意思?
    • 这个值没有什么特别之处,因为正如你所说,阈值是自动选择的。该值被忽略。见github.com/opencv/opencv/blob/master/modules/imgproc/src/…
    • 如何使用cv2将得到的二进制转成灰度图?
    • 当您使用 THRESH_OTSU 时,自动将 THRESH 自动视为零
    【解决方案2】:

    指定CV_THRESH_OTSU 会导致阈值被忽略。来自the documentation

    此外,特殊值 THRESH_OTSU 可以与上述值之一组合。在这种情况下,该函数使用 Otsu 算法确定最佳阈值,并使用它代替指定的 thresh 。该函数返回计算的阈值。目前,Otsu 的方法仅适用于 8 位图像。

    此代码从相机读取帧,并在值 20 处执行二进制阈值。

    #include "opencv2/core/core.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    
    using namespace cv;
    
    int main(int argc, const char * argv[]) {
    
        VideoCapture cap; 
        if(argc > 1) 
            cap.open(string(argv[1])); 
        else 
            cap.open(0); 
        Mat frame; 
        namedWindow("video", 1); 
        for(;;) {
            cap >> frame; 
            if(!frame.data) 
                break; 
            cvtColor(frame, frame, CV_BGR2GRAY);
            threshold(frame, frame, 20, 255, THRESH_BINARY);
            imshow("video", frame); 
            if(waitKey(30) >= 0) 
                break;
        }
    
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      方法 1

      在将灰度图像转换为二值图像时,我们通常使用cv2.threshold() 并手动设置阈值。有时为了得到一个不错的结果,我们会选择 Otsu 的二值化

      我在阅读一些博客文章时遇到了一个小技巧。

      1. 将彩色 (RGB) 图像转换为灰度。
      2. 获取灰度图像的中值。
      3. 选择比中位数高 33% 的阈值

      为什么是 33%?

      这是因为 33% 适用于大多数图像/数据集。

      您也可以通过将median 替换为mean 来制定相同的方法。

      方法2

      另一种方法是从平均值(正值或负值)取x 的标准差数(std);并设置阈值。所以它可能是以下之一:

      • th1 = mean - (x * std)
      • th2 = mean + (x * std)

      注意:在应用阈值之前,建议局部增强灰度图像的对比度(参见CLAHE)。

      【讨论】:

      • 能否将代码sn-p显示为(2)获取灰度图像的中值?
      • @thewaywewere Yu 可以像这样使用numpy 中的功能:np.median(gray_image)
      • 感谢分享(2)。
      【解决方案4】:

      对于那些做视频的人,我根据@tsh 拼凑了以下内容:

      import cv2 as cv
      import numpy as np
      
      def nothing(x):pass
      
      cap = cv.VideoCapture(0)
      cv.namedWindow('videoUI', cv.WINDOW_NORMAL)
      cv.createTrackbar('T','videoUI',0,255,nothing)
      
      while(True):
          ret, frame = cap.read()
          vid_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
          thresh = cv.getTrackbarPos('T','videoUI');
          vid_bw = cv.threshold(vid_gray, thresh, 255, cv.THRESH_BINARY)[1]
      
          cv.imshow('videoUI',cv.flip(vid_bw,1))
      
          if cv.waitKey(1) & 0xFF == ord('q'):
              break
      
      cap.release()
      cv.destroyAllWindows()
      

      结果:

      【讨论】:

        【解决方案5】:

        只需编写以下代码 sn-p 即可将 OpenCV 图像转换为灰度图像

        import cv2
        image = cv2.imread('image.jpg',0)
        cv2.imshow('grey scale image',image)
        

        注意 image.jpg 和代码必须保存在同一个文件夹中。

        注意:

        • ('image.jpg') 给出一个 RGB 图像
        • ('image.jpg',0) 提供灰度图像。

        【讨论】:

        • 灰度不是黑白的!
        【解决方案6】:

        注意,如果您使用cv.CV_THRESH_BINARY,则表示每个大于阈值的像素都成为 maxValue(在您的情况下为 255),否则该值为 0。显然,如果您的阈值为 0,则所有内容都变为白色(maxValue = 255),如果值为 255 一切都变黑(即 0)。

        如果您不想计算阈值,可以使用 Otsu 的方法。但是这个算法在 OpenCV 的实现中只适用于 8 位图像。如果您的图像是 8 位,请使用如下算法:

        cv.Threshold(im_gray_mat, im_bw_mat, threshold, 255, cv.CV_THRESH_BINARY | cv.CV_THRESH_OTSU);

        如果你有一个 8 位图像,无论阈值是多少。

        【讨论】:

          【解决方案7】:

          这是我在网上找到的两行代码,可能对初学者有帮助

          # Absolute value of the 32/64
          abs_image_in32_64 = np.absolute(image_in32_64)
          
          image_8U = np.uint8(abs_image_in32_64)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-09-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-04-21
            • 2021-02-27
            • 2021-02-26
            相关资源
            最近更新 更多