Calculate percentage of certain colors in an image

Asked

Viewed 1,677 times

4

I have a program that reads an image and checks if there are certain colors in that image, if it does paint each pixel a certain color. I couldn’t find materials on the Internet that could help me, just this one page that has a solution using histograms, but I did not understand how this is done even with the code available. Is it really possible to use histograms? Is there any other easier way to calculate the color percentage of the image? I tried to use a rule of three to calculate but returns absurd values.

Code snippet:

img = cv2.imread("IF23-1-2018.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, imgThresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
somenteAsfalto = cv2.inRange(img, asfaltoMax, asfaltoMin)
somenteTerra = cv2.inRange(img, terraMax, terraMin)
somenteVerde = cv2.inRange(img, verdeMax, verdeMin)

for i in range(0, altura):
    for j in range(0, largura):
        if somenteAsfalto[i,j] == imgThresh[i,j]:
            #pinta de vermelho onde tem asfalto
            img[i,j] = vermelho
            contAsfalto += 1
        if somenteTerra[i,j] == imgThresh[i,j]:
            #pinta de amarelo onde tem terra
            img[i,j] = amarelo
            contTerra += 1
        if somenteVerde[i,j] == imgThresh[i,j]:
            #pinta de violeta onde tem verde
            img[i,j] = violeta
            contVerde += 1
        if imgThresh[i,j] == 1 and imgThresh[i,j] == 0:
            img[i,j] = verde
            cont += 1
        if imgThresh[i,j] != somenteTerra[i,j]:
            img[i,j] = verdeCons

contNatural = contVerde + contTerra
contConstruido = contAsfalto + construido
porcVerde = (100*contVerde)/qntPixels
porcConst = (100*construido)/qntPixels
print("Pixels de asfalto: {}\nPixels de Terra: {}\nPixels onde tem verde: {}".format(contAsfalto, contTerra, contVerde))
print("Tamanho da imagem: {}".format(qntPixels))
print("Contador construido: {}\nContador contVerde: {}".format(construido, contVerde))
print("Porcentagem construída: {}%\nPorcentagem verde: {}%".format(porcConst, porcVerde))
print("DEU RUIM nº {}".format(cont))

Imagem de entrada

Input image

Imagem de saída

Output image

  • As you defined the colors of the asphalt ceiling, would have like to find something half light brown?

  • I used an image manipulation program to pick up the minimum and maximum colors (in RGB) of the object I want to identify

  • got it, paid program?

  • 1

    No, I used Gimp, which is free. Follow its official website: https://www.gimp.org/

  • Shut up, thanks brother

1 answer

2


Contar Pixels

As the function inRange() is used, pixels can be counted with the function countNonZero().

Then the amount of pixels obtained in each inRange may be obtained as follows::

pixelsAsfalto = cv2.countNonZero(somenteAsfalto)
pixelsTerra = cv2.countNonZero(somenteTerra)
pixelsVerde = cv2.countNonZero(somenteVerde)

And the total amount of pixels in the image:

pixelsTotal = img.size

By dividing each pixel amount by the total amount, you get the percentage.

Code

Then the code would look like this:

import cv2
import numpy as np
import matplotlib.pyplot as plt

def mostrar_inRange(img, mask):
    imask = mask > 0
    sliced = np.zeros_like(img, np.uint8)
    sliced[imask] = img[imask]
    plt.subplot(211)
    plt.imshow(sliced)
    plt.subplot(212)
    plt.imshow(img)
    plt.show()

img = cv2.imread("IF23-1-2018.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, imgThresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

somenteAsfalto = cv2.inRange(img, asfaltoMax, asfaltoMin)
somenteTerra = cv2.inRange(img, terraMax, terraMin)
somenteVerde = cv2.inRange(img, verdeMax, verdeMin)

pixelsAsfalto = cv2.countNonZero(somenteAsfalto)
pixelsTerra = cv2.countNonZero(somenteTerra)
pixelsVerde = cv2.countNonZero(somenteVerde)

pixelsTotal = img.size

mostrar_inRange(img, somenteAsfalto)
mostrar_inRange(img, somenteTerra)
mostrar_inRange(img, somenteVerde)

print('% Asfalto: ', (pixelsAsfalto/pixelsTotal)*100)
print('% Terra: ', (pixelsTerra /pixelsTotal)*100)
print('% Verde: ', (pixelsVerde/pixelsTotal)*100)

Observing: Grayscale color segmentation is not the best option, as the image is colored the best would be to perform this in the HSV color space. But the image quality is also not the best and the color of asphalt is very similar to the roof of the houses... So segmentation should be refined in other ways, besides using color segmentation. An alternative to finding asphalt would be to limit the search interval with the use of Hough Lines.

  • When asking to print the separate percentage of Asphalt, Earth and Green (in the last three lines) print a matrix for each

  • I used the wrong variable, the correct ones would be the variables pixelsVAR and not somenteVAR, fix the code.

  • It worked, thank you very much!!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.