I am triyng calculate the area of the white pixels in this image:
My code :
import cv2
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread("tepsi.jpg")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv,(21, 10, 15), (30, 255, 255) )
cv2.imshow("orange", mask)
cv2.waitKey()
cv2.destroyAllWindows()
How can I solve this problem? Actually my purpose is to find empty areas of food tray.
Thank you for your answers.
Thanks for your advices, i found a solution for my problem for above picture. But i will try your advices...
Note: My tray is white area and it is constant for now.
My solution :
import numpy as np
import cv2
image = cv2.imread("petibor_biskuvi.png")
dimensions = image.shape
height= image.shape[0]
width = image.shape[1]
size = height*width
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0)
_,thresh = cv2.threshold(gray,150,255,cv2.THRESH_BINARY_INV)
cnts, hier = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
size_elements = 0
for cnt in cnts:
cv2.drawContours(image,cnts, -1, (0, 0, 255), 3)
size_elements += cv2.contourArea(cnt)
print(cv2.contourArea(cnt))
cv2.imshow("Image", image)
print("size elements total : ", size_elements)
print("size of pic : ", size)
print("rate of fullness : % ", (size_elements/size)*100)
cv2.waitKey(0)
This is one option. Since white in BGR is (255, 255, 255), id suggest you convert the image to a boolean true where each (independent) channel equals to 255:
b, g, r = cv2.split(img)
wb = b == 255
wg = g == 255
wr = r == 255
The value of all of the channels must be 255 (True) for the same pixel, so, use np.bitwise_and:
white_pixels_if_true = np.bitwise_and(wb, np.bitwise_and(wg, wr))
Finally, get the count of the true value and the size of the image and find the percentage of white pixels:
img_size = r.size
white_pixels_count = np.sum(white_pixels_if_true)
white_area_ratio = white_pixels_count / img_size
Given the area of the image you can multiply the area by the white_area_ratio to get the white area.
Related
picture to be detected - different color
For a picture like above, the lines are blue, I use mask to get the contours of these lines, please see below code:
img = cv2.imread("./more5.png")#"https://i.stack.imgur.com/LiLPv.png"
blueLower = np.array([50,50,50])
blueUpper = np.array([130,255,255])
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
blue_mask = cv2.inRange(hsv, blueLower, blueUpper)
blue = cv2.bitwise_and(img ,img ,mask=blue_mask)
contours, hierarchy = cv2.findContours(preprocess(blue), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
Lines detected
complete code:
import numpy as np
import cv2
def preprocess(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_blur = cv2.GaussianBlur(img_gray, (5, 5), 1)
img_canny = cv2.Canny(img_blur, 50, 50) # edge cascade
kernel = np.ones((3, 3))
img_dilate = cv2.dilate(img_canny, kernel, iterations=1)
img_erode = cv2.erode(img_dilate, kernel, iterations=1)
return img_erode
# BGR to HSV to LAB to ...
def find_tip(points, convex_hull):
length = len(points)
indices = np.setdiff1d(range(length), convex_hull)
for i in range(2):
j = indices[i] + 2
if j > length - 1:
j = length - j
if np.all(points[j] == points[indices[i - 1] - 2]):
return tuple(points[j])
img = cv2.imread("./more5.png")
blueLower = np.array([50,50,50])
blueUpper = np.array([130,255,255])
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
blue_mask = cv2.inRange(hsv, blueLower, blueUpper)
blue = cv2.bitwise_and(img ,img ,mask=blue_mask)
contours, hierarchy = cv2.findContours(preprocess(blue), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
print(f"Contours size {len(contours)}") #
for cnt in contours:
peri = cv2.arcLength(cnt, True) #
approx = cv2.approxPolyDP(cnt, 0.004 * peri, True) #
hull = cv2.convexHull(approx, returnPoints=False)
sides = len(hull) #
if 6 > sides > 3 and sides + 2 == len(approx):
arrow_tip = find_tip(approx[:,0,:], hull.squeeze())
if arrow_tip:
cv2.drawContours(img, [cnt], -1, (0, 255, 0), 3)
cv2.circle(img, arrow_tip, 3, (0, 0, 255), cv2.FILLED)
cv2.imshow("Image", img)
cv2.waitKey(0)
However, if the line and the connected shape is the SAME color (please see the picture below), this method does NOT work anymore, how can I detect the lines from such a picture? Thanks for any ideas!
picture to be detected - same color
If your graph is a tree (it does not has closed circuits), then only the lines are connected to the same area on both sides.
If you paint the external area of the same color, only the lines will have the same color on both sides
Then you can do a convolution to have the lines averaged with the external space color, and the other lines averaged with the internal spaces color
import matplotlib.pyplot as plt
import numpy as np
#download the example image from this webpage
from PIL import Image as Pim
from io import BytesIO
import requests
photoURL="https://i.stack.imgur.com/LiLPv.png"
response = requests.get(photoURL)
image = np.array(Pim.open(BytesIO(response.content)).convert('L')) # Convert to greyscale
#mask to only 2 colors
gray=128
black=0
Monochrome = lambda t: gray if t!=image[0,0] else black #If color<>upper left color, then it is 0, else is 1
vfunc = np.vectorize(Monochrome)
image=vfunc(image)
#fill the external space with the same color as the upper left pixel
import cv2
UpperLeftPixel=(0,0)
AdjacentColor=255#White
imajeAdjacent=cv2.floodFill(image, None, UpperLeftPixel, AdjacentColor)
#convolution to average colors of lines with neighbor spaces
averagingFilter=np.ones(shape=(9,9))/9**2
import scipy
from scipy.signal import convolve2d as conv2d
image=conv2d(image,averagingFilter, mode="same")
plt.imshow(image)
plt.show()
I'm trying to implement identification of optic nerve glioma identification using python and openCV.
I need to do the following steps in order for me to classify optic nerve glioma successfully.
Find the brightest part of an image and put a circle on it using cv2.circle - Done
Calculate the white part on the image inside cv2.circle - Needs help
Here's my code for identifying the brightest part of the image
gray = cv2.GaussianBlur(gray, (371, 371), 0)
(minVal, maxVal, minLoc, maxLoc) = cv2.minMaxLoc(gray)
image = orig.copy()
cv2.circle(image, maxLoc, 371, (255, 0, 0), 2)
sought = [254,254,254]
amount = 0
for x in range(image.shape[0]):
for y in range(image.shape[1]):
b, g, r = image[x, y]
if (b, g, r) == sought:
amount += 1
print(amount)
image = imutils.resize(image, width=400)
# display the results of our newly improved method
cv2.imshow("Optic Image", image)
cv2.waitKey(0)
The code above returns the following output
What I'm trying to do now is to identify the size of the white region of the image inside the cv2.circle.
Thank you so much!
I am not sure what you consider as "white", but here is one way to do the counting in Python/OpenCV. Simply read the image. Convert to grayscale. Threshold it at some level. Then just count the number of white pixels in the thresholded image.
If I use your output image for my input (after removing your white border):
import cv2
import numpy as np
# read image
img = cv2.imread('optic.png')
# convert to HSV and extract saturation channel
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# threshold
thresh = cv2.threshold(gray, 175, 255, cv2.THRESH_BINARY)[1]
# count number of white pixels
count = np.sum(np.where(thresh == 255))
print("count =",count)
# write result to disk
cv2.imwrite("optic_thresh.png", thresh)
# display it
cv2.imshow("IMAGE", img)
cv2.imshow("THRESH", thresh)
cv2.waitKey(0)
Thresholded image:
Count of white pixels in threshold:
count = 1025729
I am still not sure what you consider as white and what you consider as the yellow circle. But here is another attempt using Python/OpenCV.
Read the input
Convert the input to the range 0 to 1 as 1D data
Use kmeans clustering to reduce the number of colors and convert back to range 0 to 255 as 2D image
Use inRange color thresholding to isolate the "yellow" area
Clean it up with morphology and get the contour
Get the minimum enclosing circle center and radius and bias the center a little
Draw an unfilled white circle on the input
Draw a white filled circle on a black background as a circle mask for the yellow area
Convert the input to grayscale
Threshold the grayscale image
Apply the mask to the thresholded grayscale image
Count the number of white pixels
Input:
import cv2
import numpy as np
from sklearn import cluster
# read image
img = cv2.imread('optic.png')
h, w, c = img.shape
# convert to range 0 to 1
image = img.copy()/255
# reshape to 1D array
image_1d = image.reshape(h*w, c)
# do kmeans processing
kmeans_cluster = cluster.KMeans(n_clusters=int(5))
kmeans_cluster.fit(image_1d)
cluster_centers = kmeans_cluster.cluster_centers_
cluster_labels = kmeans_cluster.labels_
# need to scale result back to range 0-255
newimage = cluster_centers[cluster_labels].reshape(h, w, c)*255.0
newimage = newimage.astype('uint8')
# threshold brightest region
lowcolor = (150,180,230)
highcolor = (170,200,250)
thresh1 = cv2.inRange(newimage, lowcolor, highcolor)
# apply morphology open and close
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7,7))
thresh1 = cv2.morphologyEx(thresh1, cv2.MORPH_OPEN, kernel, iterations=1)
thresh1 = cv2.morphologyEx(thresh1, cv2.MORPH_CLOSE, kernel, iterations=1)
# get contour
cntrs = cv2.findContours(thresh1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
c = cntrs[0]
# get enclosing circle and bias center, if desired, since it is slightly offset (or alternately, increase the radius)
bias = 5
center, radius = cv2.minEnclosingCircle(c)
cx = int(round(center[0]))-bias
cy = int(round(center[1]))+bias
rr = int(round(radius))
# draw filled circle over black and also outline circle over input
mask = np.zeros_like(img)
cv2.circle(mask, (cx,cy), rr, (255, 255, 255), -1)
circle = img.copy()
cv2.circle(circle, (cx,cy), rr, (255, 255, 255), 1)
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# threshold gray image
thresh2 = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)[1]
# apply mask to thresh2
thresh2 = cv2.bitwise_and(thresh2, mask[:,:,0])
# count number of white pixels
count = np.sum(np.where(thresh2 == 255))
print("count =",count)
# write result to disk
#cv2.imwrite("optic_thresh.png", thresh)
cv2.imwrite("optic_kmeans.png", newimage)
cv2.imwrite("optic_thresh1.png", thresh1)
cv2.imwrite("optic_mask.png", mask)
cv2.imwrite("optic_circle.png", circle)
cv2.imwrite("optic_thresh2.png", thresh2)
# display it
cv2.imshow("IMAGE", img)
cv2.imshow("KMEANS", newimage)
cv2.imshow("THRESH1", thresh1)
cv2.imshow("MASK", mask)
cv2.imshow("CIRCLE", circle)
cv2.imshow("GRAY", gray)
cv2.imshow("THRESH2", thresh2)
cv2.waitKey(0)
kmeans image:
inRange threshold image:
Circle on input:
Circle mask image:
Masked threshold image:
Count Results:
count = 443239
This is the imageI am trying to give proper shape to the images in my folder but unable to get that perfect result. Following is one type of example:
Following is the coding that I have done for my folder containing this type of images:
''''code''''
import cv2
import numpy as np
import glob
path = r'C:\Users\User\Desktop\A\*.jpg'
def k_function(image,k):
z= image.reshape((-1,4))
z=np.float32(z)
criteria = (cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
ret,label,center=cv2.kmeans(z,k,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((image.shape))
return res2
def noise_function(image):
kernel = np.ones((2, 2), np.uint8)
closing = cv2.morphologyEx(image, cv2.MORPH_CLOSE,
kernel, iterations = 2)
bg = cv2.dilate(closing, kernel, iterations = 1)
dist_transform = cv2.distanceTransform(closing, cv2.DIST_L2, 0)
ret, fg = cv2.threshold(dist_transform, 0.02
* dist_transform.max(), 255, 0)
return fg
def filling(thresh):
im_floodfill = thresh.copy()
h, w = thresh.shape[:2]
mask = np.zeros((h+2, w+2), np.uint8)
cv2.floodFill(im_floodfill, mask,(60,60),255);
im_floodfill_inv = cv2.bitwise_not(im_floodfill)
n = thresh | im_floodfill_inv
return n
for i, img in enumerate(glob.glob(path)):
img1 = cv2.imread(img)
n = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
b= k_function(n,2)
nm, thresh1 = cv2.threshold(b, 127, 255, cv2.THRESH_BINARY_INV);
fill = filling(thresh1)
noise = noise_function(fill)
cv2.imwrite(r'C:\Users\User\Desktop\New folder\image{}.jpg'.format(i),noise)
Try using copyMakeBorder to make a border. It looks like you're trying to use floodFill and I've never figured out how that is supposed to work.
import cv2
image = cv2.imread('elbow.png')
image = cv2.copyMakeBorder(image, 10, 0, 0, 10, cv2.BORDER_CONSTANT)
cv2.imwrite('elbow_border.png', image)
elbow.png:
elbow_border.png:
I would approach it a bit differently in Python/OpenCV. I would convert to HSV and threshold the saturation channel. Then use morphology open to smooth outline.
Input (cropped from your post):
import cv2
# load image as HSV and select saturation
img = cv2.imread("finger.png")
sat = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)[:,:,1]
# threshold the saturation channel
ret, thresh = cv2.threshold(sat,25,255,0)
# apply morphology open to smooth the outline
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (19,19))
smoothed = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
# write result to disk
cv2.imwrite("finger_smoothed.png", smoothed)
cv2.imshow("SAT", sat)
cv2.imshow("THRESH", thresh)
cv2.imshow("SMOOTHED", smoothed)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
I've written some code, to crop an object (in this case the Data Matrix Code) from an image:
import numpy as np
import cv2
image = cv2.imread("datamatrixc.png")
img_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
img_height, img_width = image.shape[:2]
WHITE = [255, 255, 255]
# Threshold filter
ret, thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
# Get Contours
_, contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Get Last element of the contours object
max = len(contours) - 1
cnt = contours[max]
# Get coordinates for the bounding box
x, y, w, h = cv2.boundingRect(cnt)
image_region = image[ int(((img_height / 2) - h) / 2) : int(((img_height / 2) - h) / 2 + h), int(x): int(x + w) ]
dmc = cv2.copyMakeBorder(image_region, 10, 10, 10, 10, cv2.BORDER_CONSTANT, value = WHITE)
cv2.imshow("Test", dmc)
cv2.waitKey(0)
cv2.destroyAllWindows()
The code works fine and I received as result:
However, the next image is a little more complicated.
I receive the same result as in the previous image, but I have no idea how to detect the two other objects.
Is there an easier way every object showing in its window?
For this specific image take the biggest contours you have and check if the object is 4 sided shape.If the half-point between the bounding box's corners (see pairs below) is in the contour array then voila, problem solved.
Pairs : TopRight-TopLeft, TopRight-BottomRight, TopLeft-BottomLeft, BottomLeft-BottomRight
Or you could check if there pixels that are not black/white inside the bounding box ?
And for the ploting individualy just slap a for on what you allready have
How about this?
import numpy as np
import cv2
image = cv2.imread("datamatrixc.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, bin_img = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
kernel = np.ones((3,3),np.uint8)
closing = cv2.morphologyEx(bin_img, cv2.MORPH_CLOSE, kernel, iterations=4)
n_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(bin_img)
size_thresh = 5000
for i in range(1, n_labels):
if stats[i, cv2.CC_STAT_AREA] >= size_thresh:
print(stats[i, cv2.CC_STAT_AREA])
x = stats[i, cv2.CC_STAT_LEFT]
y = stats[i, cv2.CC_STAT_TOP]
w = stats[i, cv2.CC_STAT_WIDTH]
h = stats[i, cv2.CC_STAT_HEIGHT]
cv2.imshow('img', image[y:y+h, x:x+w])
cv2.waitKey(0)
I have a big image of shape where i'm looking to overlap an image on a shape based on the contour
I have this image
I have this contur where it is detecting the shape and color of the image
I want to place an image on this shape
I want to custom resize the image
Out Put Desired:-
Code:-
if color == "blue" and shape == "pentagon":
A_img = cv2.imread("frame.png")
print(A_img)
x_offset=y_offset=50
B_img[y_offset:y_offset+A_img.shape[0], x_offset:x_offset+A_img.shape[1]] = A_img
That code is not working the monkey is getting printed on the top left
I have a working solution. Hope it is what you were looking for.
Code:
import cv2
import numpy as np
image = cv2.imread('C:/Users/524316/Desktop/shapes.png', 1)
monkey = cv2.imread('C:/Users/524316/Desktop/monkey.png', 1)
image2 = image.copy()
image3 = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)[1]
#cv2.imshow('thresh', thresh)
_, cnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in cnts:
#---- making sure to avoid small unwanted contours ---
if cv2.contourArea(c) > 150:
#--- selecting contours having 5 sides ---
if len(cv2.approxPolyDP(c, 0.04 * cv2.arcLength(c, True), True)) == 5:
cv2.drawContours(image2, [c], -1, (0, 255, 0), 2)
#--- finding bounding box dimensions of the contour ---
x, y, w, h = cv2.boundingRect(c)
print(x, y, w, h)
#--- overlaying the monkey in place of pentagons using the bounding box dimensions---
image3[y:y+h, x:x+w] = cv2.resize(monkey, (np.abs(x - (x+w)), np.abs(y - (y+h))))
cv2.imshow('image2', image2)
cv2.imshow('image3', image3)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result: