I have an image and I want the image recognition to pick up quadrilaterals/trapezoid-like polygons from the image. What I want the bounding box to do is to create boxes around areas.
Original image
Contours drawn on image
Problem area
What I want it to look like at the top
From the image, it goes around the specific objects in the picture but I want it to skip those and just create boxes instead. Around the bottom of the image, it is doing what I want it to do, create boxes around the 'blocks' in the image.
import cv2
import numpy as np
# read image
img = cv2.imread("map3.png")
imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
_,thresh = cv2.threshold(imgray, 110, 255,
cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
area = cv2.contourArea(contour)
if area > 500:
approx = cv2.approxPolyDP(contour, .002*cv2.arcLength(contour, True), True)
if len(approx) >= 4:
cv2.drawContours(img, [approx], -1, (0, 0, 255), 2)
cv2.imshow("IMAGE", img)
cv2.waitKey(0)
Related
I have the following image: mask
I'm trying separate each white piece into its own image. My approach is to find the contours, iterate over them and fill each one with white color then save the new image.
So far, I've found the contours after using Canny Edge Detection: contours
But I can't seem to fill them all on the inside, since the edges are not fully connected:contours filled
Is there a way to fill in the contours without using dilation/erosion? I intend to preserve the image as it is, not altering it more than needed.
I've used the following code.
import cv2
import numpy as np
def get_blank_image(image):
return np.zeros((image.shape[0], image.shape[1], 3), np.uint8)
# Let's load a simple image with 3 black squares
image = cv2.imread('img.png')
cv2.waitKey(0)
blank_image = get_blank_image(image)
# cv2.imshow('blank', blank_image)
# Grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Find Canny edges
edged = cv2.Canny(gray, 30, 50)
cv2.waitKey(0)
# Finding Contours
# Use a copy of the image e.g. edged.copy()
# since findContours alters the image
contours, hierarchy = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
good_contours = []
for con in contours:
area = cv2.contourArea(con)
if area > 10:
good_contours.append(con)
cv2.drawContours(blank_image, [con], 0, (255, 255, 255), thickness=cv2.FILLED)
# cv2.fillPoly(blank_image, pts=[con], color=(255, 255, 255))
# cv2.imshow('blank', blank_image)
# cv2.waitKey(0)
# good_contours.remove(con)
# cv2.imshow('Canny Edges After Contouring', edged)
cv2.waitKey(0)
cv2.imshow('blank', blank_image)
print("Number of Contours found = " + str(len(good_contours)))
# Draw all contours
# -1 signifies drawing all contours
cv2.drawContours(image, good_contours, -1, (0, 255, 0), 3)
cv2.imshow('Contours', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
I am trying to take out the ground floor of room image as separate one . You can assume to extract it out from there and show using basic approach. I am using Opencv instead of any segmentation approaches as i think those approaches will take time and opencv will be fast. It should work with every image means remain dynamic .
Here is right now what i am using:
Image:
Image
Code:
import cv2
import numpy as np
# Load the image
img = cv2.imread("room.jpg")
# Convert the image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Apply Gaussian blur to remove noise
blur = cv2.GaussianBlur(gray, (5, 5), 0)
# Use Canny edge detection to find edges
edges = cv2.Canny(blur, 50, 150)
# Find contours in the image
contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Sort the contours by area
contours = sorted(contours, key=cv2.contourArea, reverse=True)
# Set a minimum area for the contour to be considered
min_area = 5000
# Loop through the contours and draw only those with an area greater than min_area
for cnt in contours:
if cv2.contourArea(cnt) > min_area:
cv2.drawContours(img, [cnt], -1, (0, 255, 0), 3)
break
# Display the result
cv2.imshow("Floor", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
It is not giving desired results, It is wrong placing points. How can i sort it out, Opinions and other things would also be apprecietable.
I want to develop an algorithm to recognize through an image, if the object present in said image is a spoon, a fork, or a knife. To acomplish this I am thinking of first comparing the ratio between white and black pixels along a line and if the ratio is the same along the ROI (with a tolerance of say 30%) i can say it's a knife, if not then I move to determine if it's a spoon or a fork.
But my problem starts here, I can't control wheter or not the spoon/fork/knife comes correctly oriented or not, if it comes rotated I am afraid my algorithm needs to be able to check along rotated lines as well. I can alredy get the angle of rotation, but I don't really know what to do with it. The code I have so far is:
import cv2
import numpy as np
img = cv2.imread('GenericImages/PBL3/fork.jpg')
NC = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, threshold = cv2.threshold(NC, 50, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Draws contours
for c in contours:
if cv2.contourArea(c) < 1000:
continue
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(img, [box], 0, (0, 191, 255), 2)
cv2.imshow('ROI', img)
cv2.waitKey(0)
I would like to find the contour of the rectangular photograph inside of the object. I've tried using the corner detection feature of OpenCV, but to no avail. I also tried to find all the contours using findContours, and filter out the contours with more (or less) than 4 edges, but this also didn't lead anywhere.
I have a sample scan here.
I have a solution for you, but it involves a lot of steps. Also, it may not generalize that well. It does work pretty good for your image though.
First a grayscale and threshold is made and findContours is used to create a mask of the paper area. That mask is inverted and combined with the original image, which makes the black edges white. A new grayscale and threshold is made on the resulting image, which is then inverted so findContours can find the dark pixels of the photo. A rotated box around the largest contours is selected, which is the area you seek.
I added a little extra, which you may not need, but could be convenient: perspectivewarp is applied to the box, so the area you want is made into a straight rectangle.
There is quite a lot happening, so I advise you to take some time a look at the intermediate steps, to understand what happens.
Result:
Code:
import numpy as np
import cv2
# load image
image = cv2.imread('photo.jpg')
# resize to easily view on screen, remove for final processing
image = cv2.resize(image,None,fx=0.2, fy=0.2, interpolation = cv2.INTER_CUBIC)
### remove outer black edge
# create grayscale
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# perform threshold
retr , mask = cv2.threshold(gray_image, 190, 255, cv2.THRESH_BINARY)
# remove noise
kernel = np.ones((5,5),np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# create emtpy mask
mask_2 = np.zeros(image.shape[:3], dtype=image.dtype)
# find contours
ret, contours, hier = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# draw the found shapes (white, filled in ) on the empty mask
for cnt in contours:
cv2.drawContours(mask_2, [cnt], 0, (255,255,255), -1)
# invert mask and combine with original image - this makes the black outer edge white
mask_inv_2 = cv2.bitwise_not(mask_2)
tmp = cv2.bitwise_or(image, mask_inv_2)
### Select photo - not inner edge
# create grayscale
gray_image2 = cv2.cvtColor(tmp, cv2.COLOR_BGR2GRAY)
# perform threshold
retr, mask3 = cv2.threshold(gray_image2, 190, 255, cv2.THRESH_BINARY)
# remove noise
maskX = cv2.morphologyEx(mask3, cv2.MORPH_CLOSE, kernel)
# invert mask, so photo area can be found with findcontours
maskX = cv2.bitwise_not(maskX)
# findcontours
ret, contours2, hier = cv2.findContours(maskX, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# select the largest contour
largest_area = 0
for cnt in contours2:
if cv2.contourArea(cnt) > largest_area:
cont = cnt
largest_area = cv2.contourArea(cnt)
# find the rectangle (and the cornerpoints of that rectangle) that surrounds the contours / photo
rect = cv2.minAreaRect(cont)
box = cv2.boxPoints(rect)
box = np.int0(box)
print(rect)
#### Warp image to square
# assign cornerpoints of the region of interest
pts1 = np.float32([box[1],box[0],box[2],box[3]])
# provide new coordinates of cornerpoints
pts2 = np.float32([[0,0],[0,450],[630,0],[630,450]])
# determine and apply transformationmatrix
M = cv2.getPerspectiveTransform(pts1,pts2)
result = cv2.warpPerspective(image,M,(630,450))
#draw rectangle on original image
cv2.drawContours(image, [box], 0, (255,0,0), 2)
#show image
cv2.imshow("Result", result)
cv2.imshow("Image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
So I am currently working on a project where I need to find the area in terms of cm of a particular curve.The problem is the curve has more than one colors each representing a different values
Something Like This
Can someone help me do it? There are more than one such curves in the image. How to simultaneously calculate all of them in Python.
You can use the following code to print area in terms of pixels. To get the area in cm^2, you need to know the relationship between pixels and actual length.
The following code prints the area of largest blob in the image.
To get the area of all the blobs in the image, just replace [c] with contours
import cv2
import numpy as np
img = cv2.imread("image.png", 0)
blank = np.zeros_like(img)
ret, thresh = cv2.threshold(img, 0 ,255, cv2.THRESH_BINARY)
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
if( len(contours) != 0 ):
c = max(contours, key = cv2.contourArea)
cv2.drawContours(blank, [c], -1, 255, -1)
print cv2.countNonZero(blank)
cv2.imshow("img", blank)
cv2.waitKey(0)
cv2.destroyAllWindows()
Edit:
import cv2
import numpy as np
img = cv2.imread("images.png", 0)
blank = np.zeros_like(img)
ret, thresh = cv2.threshold(img, 0 ,255, cv2.THRESH_BINARY)
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for i in range(len(contours)):
cv2.drawContours(blank, contours[i], -1, 255, -1)
print "area of contour " + str(i)+" = " + str(cv2.contourArea(contours[i]))
cv2.imshow("img", blank)
cv2.waitKey(0)
cv2.destroyAllWindows()
1, separate out the different colored blobs. They look like they are generated by some other mapping software so presumably the colors are fixed and known. Make a new image for each color
2, For an image that contains only blobs of a fixed color and a black background you can make contours of the outlines (see findContours). Opencv will give you a separate contour for each blob.
3, Calculate the area of each contour -there is an opencv function to do this.