Ask Your Question
0

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

asked 2013-08-14 12:12:10 -0600

lenteken gravatar image

updated 2013-08-27 03:07:31 -0600

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);
            }   


        }


    }

}

edit retag flag offensive close merge delete

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 ( 2013-08-27 03:36:22 -0600 )edit

2 answers

Sort by ยป oldest newest most voted
4

answered 2013-08-14 17:03:31 -0600

Guanta gravatar image

updated 2013-08-16 11:41:47 -0600

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++;
      } 
    }
}
edit flag offensive delete link more

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 ( 2013-08-15 11:21:41 -0600 )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 ( 2013-08-16 03:35:39 -0600 )edit

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

lenteken gravatar imagelenteken ( 2013-08-16 07:24:20 -0600 )edit

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

Guanta gravatar imageGuanta ( 2013-08-16 11:44:04 -0600 )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 ( 2013-08-16 13:34:39 -0600 )edit

maybe, debugging is up do you

Guanta gravatar imageGuanta ( 2013-08-16 16:29:59 -0600 )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 ( 2013-08-27 02:56:08 -0600 )edit
3

answered 2013-08-15 09:40:11 -0600

Hansg91 gravatar image

updated 2013-08-16 12:05:42 -0600

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);
edit flag offensive delete link more

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 ( 2013-08-16 03:23:53 -0600 )edit

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

lenteken gravatar imagelenteken ( 2013-08-16 07:25:50 -0600 )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 ( 2013-08-16 12:07:24 -0600 )edit

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

Guanta gravatar imageGuanta ( 2013-08-16 12:22:56 -0600 )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 ( 2013-08-16 13:49:47 -0600 )edit

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

Guanta gravatar imageGuanta ( 2013-08-16 16:31:57 -0600 )edit

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

lenteken gravatar imagelenteken ( 2013-08-16 23:31:17 -0600 )edit

Same result of what?

Guanta gravatar imageGuanta ( 2013-08-17 03:40:08 -0600 )edit

same result value at the code you give first.

lenteken gravatar imagelenteken ( 2013-08-17 07:33:14 -0600 )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 ( 2013-08-18 13:37:56 -0600 )edit

Question Tools

Stats

Asked: 2013-08-14 12:12:10 -0600

Seen: 39,389 times

Last updated: Aug 27 '13