Ask Your Question
0

Best method to count the black and white pixels of the image.

asked Aug 14 '13

lenteken gravatar image

updated Aug 27 '13

After I masked the image and get the part I wanted. The next process is to count the black and white pixels of the unmasked part of the image but I don't know how to do it. Anyone who can give me the method to solve this.

image description

#include "opencv\cvaux.h" #include "opencv\cxmisc.h" #include "opencv\highgui.h" #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <stdlib.h>

using namespace std; using namespace cv;

int main(int, char**) { Mat threshold_output; vector<vector<point> > contours; vector<vec4i> hierarchy; RNG rng(12345);

     CvCapture* capture = cvCaptureFromCAM(0);
 cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 270);
 cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 190);

    cv::Mat frame; cv::Mat src_gray;

    while(true) {
        frame = cvQueryFrame( capture );

        cvtColor( frame,src_gray, CV_BGR2GRAY );
        medianBlur( src_gray, src_gray, 25 );
        threshold( src_gray.clone(), threshold_output, 20, 255,CV_THRESH_BINARY_INV);
        findContours( threshold_output.clone(), contours,hierarchy,CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );


        for (int i = 0; i < contours.size(); i++)
        {
            double area =contourArea(contours[i]);
            Rect rect = boundingRect(contours[i]);

            if (area >= 30 && abs(1 - ((double)rect.width /(double)rect.height)) <= 0.1)   
            {


                   Mat mask = Mat::zeros(threshold_output.rows, threshold_output.cols, CV_8UC1);
                   drawContours( mask, contours,i , Scalar::all(255), -1);
                   Mat crop(frame.rows, frame.cols, CV_8UC3);
                   crop.setTo(Scalar(255,255,255));
                   frame.copyTo(crop, mask);

                    int count_black = 0;
                    int count_white = 0;
                    int black_total;
                    int white_total;

                    for( int y = 0; y < frame.rows; y++ ) 
                    {
                      for( int x = 0; x < frame.cols; x++ ) 
                      {
                        if ( mask.at<uchar>(y,x) != 0 ) {
                          // change this to to 'src.atuchar>(y,x) == 255' 
                          // if your img has only 1 channel
                          if ( frame.at<cv::Vec3b>(y,x) == cv::Vec3b(0,0,0) ) 
                          {
                            count_black++;
                            black_total = count_black + count_black ;
                            printf("black= %d",black_total);

                          } 

                        }
                    }

                    }
                   imshow( "frame", frame );
                   imshow("crop",crop);
                   waitKey(33);
            }   


        }


    }

}

Preview: (hide)

Comments

1

Excuse me, but you have been adapting your topic for various times now, nevertheless you assigned it as solved. This is quite irritating, since it keeps popping back to the beginning and people get notices about problems. However, with each edit, you forget to mention what you are doing. Please keep an edit history to mark why it changes.

StevenPuttemans gravatar imageStevenPuttemans (Aug 27 '13)edit

2 answers

Sort by » oldest newest most voted
4

answered Aug 14 '13

Guanta gravatar image

updated Aug 16 '13

What do you mean with 'unmasked', guess the small round part, which is not red marked, then all black and white pixels in this area can be counted as follows:

int count_black = 0;
int count_white = 0;
for( int y = 0; y < src.rows; y++ ) {
  for( int x = 0; x < src.cols; x++ ) {
    if ( mask.at<uchar>(y,x) != 0 ) {
      // change this to to 'src.atuchar>(y,x) == 255' 
      // if your img has only 1 channel
      if ( src.at<cv::Vec3b>(y,x) == cv::Vec3b(255,255,255) ) {
        count_white++;
      } 
      else if ( src.at<cv::Vec3b>(y,x) == cv::Vec3b(0,0,0) ) {
        count_black++;
      } 
    }
}

Note: if you know that you deal with a binary image, than this can be accomplished easier with cv::countNonZero(), hope you got the idea.


EDIT

If you actually want the black & white pixels of the binary image 'gray', then you need to replace

findContours(gray, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

with

findContours(gray.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

(since findContours modifies the matrix). Furthermore replace each instance of 'src' with gray, i.e.:

int count_black = 0;
int count_white = 0;
for( int y = 0; y < gray.rows; y++ ) {
  for( int x = 0; x < gray.cols; x++ ) {
    if ( mask.at<uchar>(y,x) != 0 ) {
      if ( gray.at<uchar>(y,x) == 255 ) {
        count_white++;
      } 
      else {
        count_black++;
      } 
    }
}
Preview: (hide)

Comments

I add the code you suggest but I got zero values :( What do you think wrong with this code. I am newbie to opencv.

lenteken gravatar imagelenteken (Aug 15 '13)edit

I assumed you'd like to know the black & white pixels of the src-matrix. So I guess, in this area it just doesn't have any complete black or white pixels. What do you actually want to measure? The black & white pixels of your input image src, the black & white pixels of the binary image "gray", or the black & white pixels of the mask (@Hansg91 suggested a solution here)? If you actually wanted the black&white pixels of the binary image gray you have to do two steps: Replace findContours(gray, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); with findContours(gray.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); and then replace each src of the code which I proposed with gray.

Guanta gravatar imageGuanta (Aug 16 '13)edit

what do you mean replace the src ? Can you please edit the code above. Thanks :)

lenteken gravatar imagelenteken (Aug 16 '13)edit

Done, see my edit, hope it is clear now.

Guanta gravatar imageGuanta (Aug 16 '13)edit

It run successfully thanks, :) . The value I get is count_white = 450 to 598 and black_count = 0. Is the value correct?

lenteken gravatar imagelenteken (Aug 16 '13)edit

maybe, debugging is up do you

Guanta gravatar imageGuanta (Aug 16 '13)edit

I count now the black pixels. Thanks,I understand now the program. But the value I got is increment. How can I get the total pixels because I will use it in real time. The result is different when I convert it into real time. Please respond

lenteken gravatar imagelenteken (Aug 27 '13)edit
3

answered Aug 15 '13

Hansg91 gravatar image

updated Aug 16 '13

Wouldn't this work?

cv::Mat masked;
image.copyTo(masked, mask);
int count_black = cv::countNonZero(masked == 0);
int count_white = cv::countNonZero(masked == 255);
Preview: (hide)

Comments

1

I thought he'd like to know the black and white pixels of the image, not the mask, thus, your method wouldn't give the correct results. Maybe with the correct combination of cv::bitwise_and it would work though...

Guanta gravatar imageGuanta (Aug 16 '13)edit

I try this code also but this code count the black and white pixels of the mask not the image.

lenteken gravatar imagelenteken (Aug 16 '13)edit
2

Ah I see, I misunderstood that. Could you try the new code? Basically it copies the part marked by the mask in your image to the cv::Mat masked, and then counts the black and white pixels on this matrix.

Hansg91 gravatar imageHansg91 (Aug 16 '13)edit

Nice one! I always forget that copyTo has the extra mask-parameter :)

Guanta gravatar imageGuanta (Aug 16 '13)edit

I try your code but I got same value. In image.copyTo(masked, mask); image is undefined. what is the correct code for that? Sorry I am very newbie .

lenteken gravatar imagelenteken (Aug 16 '13)edit

In your case image's name is 'gray'.

Guanta gravatar imageGuanta (Aug 16 '13)edit

I used ' gray' but I got same result :(

lenteken gravatar imagelenteken (Aug 17 '13)edit

Same result of what?

Guanta gravatar imageGuanta (Aug 17 '13)edit

same result value at the code you give first.

lenteken gravatar imagelenteken (Aug 17 '13)edit

Did you copy the whole code? Or just added the two first lines? Cause the last two lines had a small change too ;)

Hansg91 gravatar imageHansg91 (Aug 18 '13)edit

Question Tools

Stats

Asked: Aug 14 '13

Seen: 39,565 times

Last updated: Aug 27 '13