[python] Converting an OpenCV Image to Black and White

How do you convert a grayscale OpenCV image to black and white? I see a similar question has already been asked, but I'm using OpenCV 2.3, and the proposed solution no longer seems to work.

I'm trying to convert a greyscale image to black and white, so that anything not absolutely black is white, and use this as a mask for surf.detect(), in order to ignore keypoints found on the edge of the black mask area.

The following Python gets me almost there, but the threshold value sent to Threshold() doesn't appear to have any effect. If I set it to 0 or 16 or 128 or 255, the result is the same, with all pixels with a value > 128 becoming white, and everything else becoming black.

What am I doing wrong?

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()

This question is related to python image-processing opencv computer-vision

The answer is


Step-by-step answer similar to the one you refer to, using the new cv2 Python bindings:

1. Read a grayscale image

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

2. Convert grayscale image to binary

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

which determines the threshold automatically from the image using Otsu's method, or if you already know the threshold you can use:

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

3. Save to disk

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

For those doing video I cobbled the following based on @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()

Results in:

enter image description here


Pay attention, if you use cv.CV_THRESH_BINARY means every pixel greater than threshold becomes the maxValue (in your case 255), otherwise the value is 0. Obviously if your threshold is 0 everything becomes white (maxValue = 255) and if the value is 255 everything becomes black (i.e. 0).

If you don't want to work out a threshold, you can use the Otsu's method. But this algorithm only works with 8bit images in the implementation of OpenCV. If your image is 8bit use the algorithm like this:

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

No matter the value of threshold if you have a 8bit image.


Approach 1

While converting a gray scale image to a binary image, we usually use cv2.threshold() and set a threshold value manually. Sometimes to get a decent result we opt for Otsu's binarization.

I have a small hack I came across while reading some blog posts.

  1. Convert your color (RGB) image to gray scale.
  2. Obtain the median of the gray scale image.
  3. Choose a threshold value either 33% above the median

enter image description here

Why 33%?

This is because 33% works for most of the images/data-set.

You can also work out the same approach by replacing median with the mean.

Approach 2

Another approach would be to take an x number of standard deviations (std) from the mean, either on the positive or negative side; and set a threshold. So it could be one of the following:

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

Note: Before applying threshold it is advisable to enhance the contrast of the gray scale image locally (See CLAHE).


Here's a two line code I found online that might be helpful for a beginner

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

image_8U = np.uint8(abs_image_in32_64)

Simply you can write the following code snippet to convert an OpenCV image into a grey scale image

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

Observe that the image.jpg and the code must be saved in same folder.

Note that:

  • ('image.jpg') gives a RGB image
  • ('image.jpg',0) gives Grey Scale Image.

Specifying CV_THRESH_OTSU causes the threshold value to be ignored. From the documentation:

Also, the special value THRESH_OTSU may be combined with one of the above values. In this case, the function determines the optimal threshold value using the Otsu’s algorithm and uses it instead of the specified thresh . The function returns the computed threshold value. Currently, the Otsu’s method is implemented only for 8-bit images.

This code reads frames from the camera and performs the binary threshold at the value 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;
}

Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to image-processing

Convert np.array of type float64 to type uint8 scaling values dlib installation on Windows 10 OpenCV - Saving images to a particular folder of choice How do I increase the contrast of an image in Python OpenCV OpenCV & Python - Image too big to display TypeError: Image data can not convert to float Extracting text OpenCV c++ and opencv get and set pixel color to Mat cv2.imshow command doesn't work properly in opencv-python How does one convert a grayscale image to RGB in OpenCV (Python)?

Examples related to opencv

Real time face detection OpenCV, Python OpenCV TypeError: Expected cv::UMat for argument 'src' - What is this? OpenCV !_src.empty() in function 'cvtColor' error ConvergenceWarning: Liblinear failed to converge, increase the number of iterations How do I install opencv using pip? Access IP Camera in Python OpenCV ImportError: libSM.so.6: cannot open shared object file: No such file or directory Convert np.array of type float64 to type uint8 scaling values How to import cv2 in python3? cmake error 'the source does not appear to contain CMakeLists.txt'

Examples related to computer-vision

How to predict input image using trained model in Keras? How do I increase the contrast of an image in Python OpenCV How to verify CuDNN installation? OpenCV Error: (-215)size.width>0 && size.height>0 in function imshow How to draw a rectangle around a region of interest in python How can I extract a good quality JPEG image from a video file with ffmpeg? Simple Digit Recognition OCR in OpenCV-Python OpenCV C++/Obj-C: Detecting a sheet of paper / Square Detection Converting an OpenCV Image to Black and White Combining Two Images with OpenCV