How to count the pixels of a certain color with OpenCV?

Multi tool use
Multi tool use












0















I'm trying to calculate the percentage of pixels in a certain color range in a picture.



I'm pretty new to OpenCV and python in general. What I've done is using the cv2.inRange() function to create a mask which I have as output. Right now I'm trying to do this with GRB color values between (0, 0, 130) and (80, 80, 255) and consider "red" every pixel whose color is in this range. So the output I get has two colors: black and red.
I used then this numpy function to get the number of non zero pixels which at this point I expected to be the number of red pixels: red_pixel = np.count_nonzero(output).



Here is the full code:



import cv2 
import numpy as np

img_name = input("What's the name of the picture? ")


img = cv2.imread(img_name)

# boundaries for the color red
boundaries = [
([0, 0, 130], [80, 80, 255])
]

for(lower, upper) in boundaries:
# creates numpy array from boundaries
lower = np.array(lower, dtype = "uint8")
upper = np.array(upper, dtype = "uint8")

# finds colors in boundaries a applies a mask
mask = cv2.inRange(img, lower, upper)
output = cv2.bitwise_and(img, img, mask = mask)

# saves the image
cv2.imwrite('2'+img_name, output)

tot_pixel = output.size
red_pixel = np.count_nonzero(output)
percentage = round(red_pixel * 100 / tot_pixel, 2)

print("Red pixels: " + str(red_pixel))
print("Total pixels: " + str(tot_pixel))
print("Percentage of red pixels: " + str(percentage) + "%")


I tested my code with four different pictures:



sea.jpg
which I'd expect to contain 0% of red. I run the program, as output I get a completely black image and the percentage is 0.00. Which is fine.



I tried then this one:



sample.jpg
I run the program and what I get for the percentage is 13.76 which I don't know if it's correct but could still be.



I tried a completely red image then: total-red.jpg
and I get 100.00 which is correct.



The strange thing happens when I try with this image:
almost-red.png



What I get running the program is this output:
2almost-red.png
which is what I expected. The percentage of non zero pixels though, is 33.07%
and I have no idea why.



Could you please help me figure out what I'm doing wrong and how I could correct the program? Thank you very much.










share|improve this question



























    0















    I'm trying to calculate the percentage of pixels in a certain color range in a picture.



    I'm pretty new to OpenCV and python in general. What I've done is using the cv2.inRange() function to create a mask which I have as output. Right now I'm trying to do this with GRB color values between (0, 0, 130) and (80, 80, 255) and consider "red" every pixel whose color is in this range. So the output I get has two colors: black and red.
    I used then this numpy function to get the number of non zero pixels which at this point I expected to be the number of red pixels: red_pixel = np.count_nonzero(output).



    Here is the full code:



    import cv2 
    import numpy as np

    img_name = input("What's the name of the picture? ")


    img = cv2.imread(img_name)

    # boundaries for the color red
    boundaries = [
    ([0, 0, 130], [80, 80, 255])
    ]

    for(lower, upper) in boundaries:
    # creates numpy array from boundaries
    lower = np.array(lower, dtype = "uint8")
    upper = np.array(upper, dtype = "uint8")

    # finds colors in boundaries a applies a mask
    mask = cv2.inRange(img, lower, upper)
    output = cv2.bitwise_and(img, img, mask = mask)

    # saves the image
    cv2.imwrite('2'+img_name, output)

    tot_pixel = output.size
    red_pixel = np.count_nonzero(output)
    percentage = round(red_pixel * 100 / tot_pixel, 2)

    print("Red pixels: " + str(red_pixel))
    print("Total pixels: " + str(tot_pixel))
    print("Percentage of red pixels: " + str(percentage) + "%")


    I tested my code with four different pictures:



    sea.jpg
    which I'd expect to contain 0% of red. I run the program, as output I get a completely black image and the percentage is 0.00. Which is fine.



    I tried then this one:



    sample.jpg
    I run the program and what I get for the percentage is 13.76 which I don't know if it's correct but could still be.



    I tried a completely red image then: total-red.jpg
    and I get 100.00 which is correct.



    The strange thing happens when I try with this image:
    almost-red.png



    What I get running the program is this output:
    2almost-red.png
    which is what I expected. The percentage of non zero pixels though, is 33.07%
    and I have no idea why.



    Could you please help me figure out what I'm doing wrong and how I could correct the program? Thank you very much.










    share|improve this question

























      0












      0








      0


      0






      I'm trying to calculate the percentage of pixels in a certain color range in a picture.



      I'm pretty new to OpenCV and python in general. What I've done is using the cv2.inRange() function to create a mask which I have as output. Right now I'm trying to do this with GRB color values between (0, 0, 130) and (80, 80, 255) and consider "red" every pixel whose color is in this range. So the output I get has two colors: black and red.
      I used then this numpy function to get the number of non zero pixels which at this point I expected to be the number of red pixels: red_pixel = np.count_nonzero(output).



      Here is the full code:



      import cv2 
      import numpy as np

      img_name = input("What's the name of the picture? ")


      img = cv2.imread(img_name)

      # boundaries for the color red
      boundaries = [
      ([0, 0, 130], [80, 80, 255])
      ]

      for(lower, upper) in boundaries:
      # creates numpy array from boundaries
      lower = np.array(lower, dtype = "uint8")
      upper = np.array(upper, dtype = "uint8")

      # finds colors in boundaries a applies a mask
      mask = cv2.inRange(img, lower, upper)
      output = cv2.bitwise_and(img, img, mask = mask)

      # saves the image
      cv2.imwrite('2'+img_name, output)

      tot_pixel = output.size
      red_pixel = np.count_nonzero(output)
      percentage = round(red_pixel * 100 / tot_pixel, 2)

      print("Red pixels: " + str(red_pixel))
      print("Total pixels: " + str(tot_pixel))
      print("Percentage of red pixels: " + str(percentage) + "%")


      I tested my code with four different pictures:



      sea.jpg
      which I'd expect to contain 0% of red. I run the program, as output I get a completely black image and the percentage is 0.00. Which is fine.



      I tried then this one:



      sample.jpg
      I run the program and what I get for the percentage is 13.76 which I don't know if it's correct but could still be.



      I tried a completely red image then: total-red.jpg
      and I get 100.00 which is correct.



      The strange thing happens when I try with this image:
      almost-red.png



      What I get running the program is this output:
      2almost-red.png
      which is what I expected. The percentage of non zero pixels though, is 33.07%
      and I have no idea why.



      Could you please help me figure out what I'm doing wrong and how I could correct the program? Thank you very much.










      share|improve this question














      I'm trying to calculate the percentage of pixels in a certain color range in a picture.



      I'm pretty new to OpenCV and python in general. What I've done is using the cv2.inRange() function to create a mask which I have as output. Right now I'm trying to do this with GRB color values between (0, 0, 130) and (80, 80, 255) and consider "red" every pixel whose color is in this range. So the output I get has two colors: black and red.
      I used then this numpy function to get the number of non zero pixels which at this point I expected to be the number of red pixels: red_pixel = np.count_nonzero(output).



      Here is the full code:



      import cv2 
      import numpy as np

      img_name = input("What's the name of the picture? ")


      img = cv2.imread(img_name)

      # boundaries for the color red
      boundaries = [
      ([0, 0, 130], [80, 80, 255])
      ]

      for(lower, upper) in boundaries:
      # creates numpy array from boundaries
      lower = np.array(lower, dtype = "uint8")
      upper = np.array(upper, dtype = "uint8")

      # finds colors in boundaries a applies a mask
      mask = cv2.inRange(img, lower, upper)
      output = cv2.bitwise_and(img, img, mask = mask)

      # saves the image
      cv2.imwrite('2'+img_name, output)

      tot_pixel = output.size
      red_pixel = np.count_nonzero(output)
      percentage = round(red_pixel * 100 / tot_pixel, 2)

      print("Red pixels: " + str(red_pixel))
      print("Total pixels: " + str(tot_pixel))
      print("Percentage of red pixels: " + str(percentage) + "%")


      I tested my code with four different pictures:



      sea.jpg
      which I'd expect to contain 0% of red. I run the program, as output I get a completely black image and the percentage is 0.00. Which is fine.



      I tried then this one:



      sample.jpg
      I run the program and what I get for the percentage is 13.76 which I don't know if it's correct but could still be.



      I tried a completely red image then: total-red.jpg
      and I get 100.00 which is correct.



      The strange thing happens when I try with this image:
      almost-red.png



      What I get running the program is this output:
      2almost-red.png
      which is what I expected. The percentage of non zero pixels though, is 33.07%
      and I have no idea why.



      Could you please help me figure out what I'm doing wrong and how I could correct the program? Thank you very much.







      python opencv






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Jan 3 at 9:02









      AezysAezys

      34




      34
























          1 Answer
          1






          active

          oldest

          votes


















          1














          Your image has three channels. Only one channel is in range in your third example almost-red.png.
          Thus we can deduct that at most 33% of the image is in range. As there is some border it has to be even less. 33.07% sounds plausible.



          If you want to check if any of the channels for each pixel is in range you have to sum up the three channels and than check for non-zero entries.






          share|improve this answer
























          • Thank you for the explanation, could you please suggest me a way to sum the three channels?

            – Aezys
            Jan 3 at 9:17











          • summed = np.sum(output, axis=2) should do the trick. Do it before counting the total pixels.

            – Mailerdaimon
            Jan 3 at 9:19













          • Awesome, it worked! Thank you a lot

            – Aezys
            Jan 3 at 9:27











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54019108%2fhow-to-count-the-pixels-of-a-certain-color-with-opencv%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          Your image has three channels. Only one channel is in range in your third example almost-red.png.
          Thus we can deduct that at most 33% of the image is in range. As there is some border it has to be even less. 33.07% sounds plausible.



          If you want to check if any of the channels for each pixel is in range you have to sum up the three channels and than check for non-zero entries.






          share|improve this answer
























          • Thank you for the explanation, could you please suggest me a way to sum the three channels?

            – Aezys
            Jan 3 at 9:17











          • summed = np.sum(output, axis=2) should do the trick. Do it before counting the total pixels.

            – Mailerdaimon
            Jan 3 at 9:19













          • Awesome, it worked! Thank you a lot

            – Aezys
            Jan 3 at 9:27
















          1














          Your image has three channels. Only one channel is in range in your third example almost-red.png.
          Thus we can deduct that at most 33% of the image is in range. As there is some border it has to be even less. 33.07% sounds plausible.



          If you want to check if any of the channels for each pixel is in range you have to sum up the three channels and than check for non-zero entries.






          share|improve this answer
























          • Thank you for the explanation, could you please suggest me a way to sum the three channels?

            – Aezys
            Jan 3 at 9:17











          • summed = np.sum(output, axis=2) should do the trick. Do it before counting the total pixels.

            – Mailerdaimon
            Jan 3 at 9:19













          • Awesome, it worked! Thank you a lot

            – Aezys
            Jan 3 at 9:27














          1












          1








          1







          Your image has three channels. Only one channel is in range in your third example almost-red.png.
          Thus we can deduct that at most 33% of the image is in range. As there is some border it has to be even less. 33.07% sounds plausible.



          If you want to check if any of the channels for each pixel is in range you have to sum up the three channels and than check for non-zero entries.






          share|improve this answer













          Your image has three channels. Only one channel is in range in your third example almost-red.png.
          Thus we can deduct that at most 33% of the image is in range. As there is some border it has to be even less. 33.07% sounds plausible.



          If you want to check if any of the channels for each pixel is in range you have to sum up the three channels and than check for non-zero entries.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 3 at 9:14









          MailerdaimonMailerdaimon

          4,64112539




          4,64112539













          • Thank you for the explanation, could you please suggest me a way to sum the three channels?

            – Aezys
            Jan 3 at 9:17











          • summed = np.sum(output, axis=2) should do the trick. Do it before counting the total pixels.

            – Mailerdaimon
            Jan 3 at 9:19













          • Awesome, it worked! Thank you a lot

            – Aezys
            Jan 3 at 9:27



















          • Thank you for the explanation, could you please suggest me a way to sum the three channels?

            – Aezys
            Jan 3 at 9:17











          • summed = np.sum(output, axis=2) should do the trick. Do it before counting the total pixels.

            – Mailerdaimon
            Jan 3 at 9:19













          • Awesome, it worked! Thank you a lot

            – Aezys
            Jan 3 at 9:27

















          Thank you for the explanation, could you please suggest me a way to sum the three channels?

          – Aezys
          Jan 3 at 9:17





          Thank you for the explanation, could you please suggest me a way to sum the three channels?

          – Aezys
          Jan 3 at 9:17













          summed = np.sum(output, axis=2) should do the trick. Do it before counting the total pixels.

          – Mailerdaimon
          Jan 3 at 9:19







          summed = np.sum(output, axis=2) should do the trick. Do it before counting the total pixels.

          – Mailerdaimon
          Jan 3 at 9:19















          Awesome, it worked! Thank you a lot

          – Aezys
          Jan 3 at 9:27





          Awesome, it worked! Thank you a lot

          – Aezys
          Jan 3 at 9:27




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54019108%2fhow-to-count-the-pixels-of-a-certain-color-with-opencv%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          3k8dMLT0v f2IVkdszleavqrL
          AwQ7j,ce267DL9,RnGUXh4,Ym0VuXliGmbgjsoFMQu2SkY7pw,bK9NOv

          Popular posts from this blog

          Monofisismo

          Angular Downloading a file using contenturl with Basic Authentication

          Olmecas