Ask Your Question

Counting black & white pixels with a threshold

asked 2015-04-28 04:44:06 -0500

Storiy gravatar image

I use ROI to work with a part of image that i am interested in, and now i want to count black & white pixels in it. Although something as simple as:

 int count_black = 0;
    int count_white = 0;
    for( int y = 0; y < imgROI.rows; y++ ) {
      for( int x = 0; x < imgROI.cols; x++ ) {
          if (<cv::Vec3b>(y,x) == cv::Vec3b(255,255,255) ) {
          else if (<cv::Vec3b>(y,x) == cv::Vec3b(0,0,0) ) {

wont work, since there is no complete white or black one's. Only various shades of gray. Is there a way to use some threshold to sort them in black or white counters? Or maybe function to increase contrast and convert them into absolute white or black colors?

edit retag flag offensive close merge delete



I do not know enough about your approach, but you can use threshold two times: one for almost white, and one for almost black, then use countNonZero to get the number of white/black pixels. Be careful to put on white all the pixels that you want (make white the almost black pixels, so you can count non zeros). Sorry, but I do not have enough time to create a nice answer

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-04-28 05:06:37 -0500 )edit

Any advice is helpful for me. Thanks for the links, i will keep an eye them right now.

Storiy gravatar imageStoriy ( 2015-04-28 06:33:19 -0500 )edit

For now did it with

  threshold( partROI1, partROI1, 80, 255, 0 );

and then just counted black & white's with previous func

Storiy gravatar imageStoriy ( 2015-04-28 07:49:42 -0500 )edit

If you have just 2 types of pixels, then you can do numOfWhitePixels = contNonZero and then numOfBlackPixels = imgROI.cols * imgROI.rows - numOfWhitePixels

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-04-28 08:42:16 -0500 )edit

I try'ed to use your way as

count_white = countNonZero(partROI1);
count_black = partROI1.cols * partROI1.rows - count_white;

but i got terminal crash with this error:

terminate called after throwing an instance of 'cv::Exception'
what():  /home/iurt/rpmbuild/BUILD/opencv- error: (-215) src.channels() ==      1 && func != 0 in function countNonZero
Storiy gravatar imageStoriy ( 2015-04-29 04:14:13 -0500 )edit

Your image partROI1 is not binary (0 and 1). Have you threshold it? How? You should use cv::THRESH_BINARY or cv::THRESH_BINARY_INV. That is why I have said you shall threshold it 2 times: one for almost white pixels (with a threshold of 240 and cv::THRESH_BINARY) and one for almost black pixels (with a threshold of 20 and cv::THRESH_BINARY_INV) and then countNonZero for each case. You can adapt your thresholds to your approach

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-04-29 06:45:42 -0500 )edit

did it for now with this code.

threshold( partROI1, partROI1, 20, 255, THRESH_BINARY );
count_black = countNonZero(partROI1);
threshold( partROI1, partROI1, 240, 255, THRESH_BINARY_INV );
count_white= countNonZero(partROI1);

since i were using a ROI of an image

cvtColor(partROI1, partROI1, CV_BGR2GRAY);


Storiy gravatar imageStoriy ( 2015-04-30 05:12:27 -0500 )edit

The error happens in the first or the second call of the countNonZero? You have some problems there:

  1. threshold( partROI1, partROI1, 20, 255, THRESH_BINARY ); is changing the initial image if you have done something like cv::Mat partROI1 = initImage(roiRect); (use initImage(roiRect).clone if that is the case)
  2. you are counting the wrong: count_black is counting the pixel that are not almost black and count_white the ones that are not almost white. (you can do some imshow s to see exactly what you are doing; the white pixels are counted)
  3. you are trying to threshold an already thresholded image here: threshold( partROI1, partROI1, 240, 255, THRESH_BINARY_INV ); and inverse it.

So, as I have said, do an imshow after each step to see exactly what are you doing

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-04-30 07:17:09 -0500 )edit

no, error doesn't show up anymore cvtColor(partROI, partROI, CV_BGR2GRAY); helped me to fix that. And yes, i were first counting the white pixels with THRESH_BINARY and then inverting them with THRESH_BINARY_INV and counting again the black ones. But you are right and this way will be more efficient

            threshold( partROI, partROI, 240, 255, THRESH_BINARY );
            count_white = countNonZero(partROI);
            count_black = partROI.cols * partROI.rows - count_white2;
Storiy gravatar imageStoriy ( 2015-04-30 07:49:34 -0500 )edit

That approach is ok, if you have just white and black pixels in the image and no gray values (that means you so not want only the white and black pixels from an image that may contain gray values too). So the problem was that you were trying to apply threshold on a RGB image...

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-04-30 08:27:00 -0500 )edit

1 answer

Sort by ยป oldest newest most voted

answered 2015-05-13 05:20:06 -0500

Storiy gravatar image

Just in case someone need's that, i add the code

            Mat  partROI;
            cvtColor(partROI, partROI, CV_BGR2GRAY);
            int count_white = 0;
            int count_black = 0;
            threshold( partROI, partROI, 200, 255, THRESH_BINARY );
            count_white = countNonZero(partyROI);
            count_black = partyROI.cols * partyROI.rows - count_white;
            cout << "white pixels = " << count_white << endl;
            cout << "black pixels = " << count_black << endl;
            cout << endl;
            imshow("Image", partROI);
edit flag offensive delete link more
Login/Signup to Answer

Question Tools

1 follower


Asked: 2015-04-28 04:44:06 -0500

Seen: 6,441 times

Last updated: May 13 '15