简体   繁体   中英

Detection of objects in nonuniform illumination in opencv C++

I am performing feature detection in a video/live stream/image using OpenCV C++. The lighting condition varies in different parts of the video, leading to some parts getting ignored while transforming the RGB images to binary images.

The lighting condition in a particular portion of the video also changes over the course of the video. I tried the 'Histogram equalization' function, but it didn't help.

I got a working solution in MATLAB in the following link:

http://in.mathworks.com/help/images/examples/correcting-nonuniform-illumination.html

However, most of the functions used in the above link aren't available in OpenCV.

Can you suggest the alternative of this MATLAB code in OpenCV C++?

OpenCV has the adaptive threshold paradigm available in the framework: http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#adaptivethreshold

The function prototype looks like:

void adaptiveThreshold(InputArray src, OutputArray dst, 
                      double maxValue, int adaptiveMethod, 
                      int thresholdType, int blockSize, double C);

The first two parameters are the input image and a place to store the output thresholded image. maxValue is the thresholded value assigned to an output pixel should it pass the criteria, adaptiveMethod is the method to use for adaptive thresholding, thresholdType is the type of thresholding you want to perform (more later), blockSize is the size of the windows to examine (more later), and C is a constant to subtract from each window. I've never really needed to use this and I usually set this to 0.

The default method for adaptiveThreshold is to analyze blockSize x blockSize windows and calculate the mean intensity within this window subtracted by C . If the centre of this window is above the mean intensity, this corresponding location in the output position of the output image is set to maxValue , else the same position is set to 0. This should combat the non-uniform illumination issue where instead of applying a global threshold to the image, you are performing the thresholding on local pixel neighbourhoods.

You can read the documentation on the other methods for the other parameters, but to get your started, you can do something like this:

// Include libraries
#include <cv.h>
#include <highgui.h>

// For convenience
using namespace cv;

// Example function to adaptive threshold an image
void threshold() 
{
   // Load in an image - Change "image.jpg" to whatever your image is called
   Mat image;
   image = imread("image.jpg", 1);

   // Convert image to grayscale and show the image
   // Wait for user key before continuing
   Mat gray_image;
   cvtColor(image, gray_image, CV_BGR2GRAY);

   namedWindow("Gray image", CV_WINDOW_AUTOSIZE);
   imshow("Gray image", gray_image);   
   waitKey(0);

   // Adaptive threshold the image
   int maxValue = 255;
   int blockSize = 25;
   int C = 0;
   adaptiveThreshold(gray_image, gray_image, maxValue, 
                     CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 
                     blockSize, C);

   // Show the thresholded image
   // Wait for user key before continuing
   namedWindow("Thresholded image", CV_WINDOW_AUTOSIZE);
   imshow("Thresholded image", gray_image);
   waitKey(0);
}

// Main function - Run the threshold function
int main( int argc, const char** argv ) 
{
    threshold();
}

adaptiveThreshold should be your first choice.

But here I report the "translation" from Matlab to OpenCV, so you can easily port your code. As you see, most of the functions are available both in Matlab and OpenCV.

#include <opencv2\opencv.hpp>
using namespace cv;

int main()
{   
    // Step 1: Read Image
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);

    // Step 2: Use Morphological Opening to Estimate the Background
    Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(15,15));
    Mat1b background;
    morphologyEx(img, background, MORPH_OPEN, kernel);

    // Step 3: Subtract the Background Image from the Original Image
    Mat1b img2;
    absdiff(img, background, img2);

    // Step 4: Increase the Image Contrast
    // Don't needed it here, the equivalent would be  cv::equalizeHist

    // Step 5(1): Threshold the Image
    Mat1b bw;
    threshold(img2, bw, 50, 255, THRESH_BINARY);

    // Step 6: Identify Objects in the Image
    vector<vector<Point>> contours;
    findContours(bw.clone(), contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);


    for(int i=0; i<contours.size(); ++i)
    {
        // Step 5(2): bwareaopen
        if(contours[i].size() > 50)
        {
            // Step 7: Examine One Object
            Mat1b object(bw.size(), uchar(0));
            drawContours(object, contours, i, Scalar(255), CV_FILLED);

            imshow("Single Object", object);
            waitKey();
        }
    }

    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM