An output image file with red contours of all objects - python

I have the following code:
import cv2 as cv
import numpy as np
image = cv.imread("input1.jpg")
img_gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
img_denoised = cv.GaussianBlur(img_gray,(5,5),2)
ret, thresh = cv.threshold(img_denoised, 216, 255, cv.THRESH_BINARY)
kernel = np.ones((1,1),np.uint8)
opening = cv.dilate(thresh, kernel)
opening = cv.erode(opening, kernel)
# detect the contours on the binary image using cv.CHAIN_APPROX_NONE
contours, hierarchy = cv.findContours(image=opening, mode=cv.RETR_TREE, method=cv.CHAIN_APPROX_NONE)
for i in contours:
x, y, w, h = cv.boundingRect(i)
cv.drawContours(image, [i], -1, (0, 0, 255), 2)
cv.imshow("A.jpg", image)
cv.waitKey(0)
cv.destroyAllWindows()
Output:
enter image description here
It only shows the stars with a red contours but I want all the text to have a red contours, including the background. Here is the original file:
enter image description here
Many thanks in advance!

I messed with this a bit and the best outcome I could get was the following, I think with some tweaking you could ignore the shading, as I'm converting it to grayscale it seems to be dropping the correct contour on the shapes, but the text is working as expected;
import cv2
import numpy as np
src = cv2.imread('c:\\input1.jpg')
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
# blur
blur = cv2.GaussianBlur(gray, (3, 3), 0)
# canny edge
canny = cv2.Canny(blur, 100, 200)
# dilate
kernel = np.ones((5, 5))
dilate = cv2.dilate(canny, kernel, iterations=1)
# find contours
contours, hierarchy = cv2.findContours(
dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# draw contours
cv2.drawContours(src, contours, -1, (0, 255, 0), 3)
cv2.imshow("a.jpg", src)
cv2.waitKey()

Related

Hand contour not precise

I wrote an OpenCV program to extract the hand out of the image precisely. But is not able to get it out correctly. Below is the code and the output and the sample image which I used to test it.
import numpy as np
import cv2
# Reading image
font = cv2.FONT_HERSHEY_COMPLEX
img2 = cv2.imread('1.bmp', cv2.IMREAD_COLOR)
# Reading same image in another
# variable and converting to gray scale.
img = cv2.imread('1.bmp', cv2.IMREAD_GRAYSCALE)
# Converting image to a binary image
# ( black and white only image).
_, threshold = cv2.threshold(img, 110, 255, cv2.THRESH_BINARY)
# Detecting contours in image.
contours, _= cv2.findContours(threshold, cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
contours1 = max(contours, key=cv2.contourArea)
# Going through every contours found in the image.
approx = cv2.approxPolyDP(contours1, 0.009 * cv2.arcLength(contours1, True), True)
# draws boundary of contours.
cv2.drawContours(img2, [approx], 0, (0, 0, 255), 5)
cv2.imshow('image2', img2)
# Exiting the window if 'q' is pressed on the keyboard.
if cv2.waitKey(0) & 0xFF == ord('q'):
cv2.destroyAllWindows()
Input image -
One of the reasons your contour is not precise is the obvious; the line where you approximated the contour. But you have also mentioned (in a comment) that lowering the approximation didn't solve the problem.
This is because you didn't blur the thresholded image, which resulted in the jagged edges. Here is an example where the thresholded image is blurred before the contour detection:
The code:
import cv2
import numpy as np
def process(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
return cv2.threshold(img_gray, 111, 255, cv2.THRESH_BINARY)[1]
def draw_contours(img):
contours, _ = cv2.findContours(process(img), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
cv2.drawContours(img, [cnt], -1, (0, 0, 255), 2)
img = cv2.imread("image.png")
draw_contours(img)
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Input image:
Output image:
Still, the contour isn't very precise. This is where the Canny edge detector comes into play:
import cv2
import numpy as np
def process(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(img_gray, 111, 255, cv2.THRESH_BINARY)
img_blur = cv2.GaussianBlur(thresh, (5, 5), 4)
img_canny = cv2.Canny(img_blur, 0, 0)
img_dilate = cv2.dilate(img_canny, None, iterations=1)
return cv2.erode(img_dilate, None, iterations=0)
def draw_contours(img):
contours, _ = cv2.findContours(process(img), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
cv2.drawContours(img, [cnt], -1, (0, 0, 255), 2)
img = cv2.imread("image.png")
draw_contours(img)
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Grey scale image to contour with isotherm lines

I have gray scale image and want to convert to intensity contour with isotherm lines, in my code I am getting only one contour and how to apply the isotherm lines?
Goal:
import numpy as np
import cv2 as cv
img = cv2.imread(path)
imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
cv.drawContours(img, contours, -1, (0,255,0), 3)
plt.imshow(img)
You're on the right track, all you have to do is just take that 127 that you hard-coded into the code, and iterate over a couple of different values. So take what you have and just add a few things (including a plug for the viridis colormap):
import numpy as np
import cv2
# I don't have your image, so I will just create a similar one.
H, W = 480, 640
img = np.zeros([H, W, 3], dtype=np.uint8)
cv2.circle(img, (W//2, H//2), 200, (255,255,255), -1)
img = cv2.GaussianBlur(img, (551, 551), 0)
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# The viridis colormap is better than the jet one you have used.
img_viridis = cv2.applyColorMap(imgray, cv2.COLORMAP_VIRIDIS)
# This for-loop allows you to draw isotherm lines at any value you want.
THRESHES = [30, 90, 170]
for val in THRESHES:
ret, thresh = cv2.threshold(imgray, val, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img_viridis, contours, -1, (0, 0, 255), 2)
cv2.imshow('img', img_viridis)
k = cv2.waitKey(0)
output:
Here is another approach in Python/OpenCV by quantizing the gray image and then getting the contours.
Read the input
Convert it to gray
Quantize it
Get Canny edge
Apply morphology close to ensure they are closed
Get the contours
Filter the contours by perimeter to remove small extraneous ones
Draw the contours on the input
Save the results
Input:
import numpy as np
import cv2
# read input
img = cv2.imread('bright_blob.png')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# do color quantization
gray = 64*((gray/64).astype(np.uint8))
# get canny edges
edges = cv2.Canny(gray, 10, 250)
# apply morphology closed to ensure they are closed
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
edges = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
# get contours
contours = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
contours = contours[0] if len(contours) == 2 else contours[1]
# filter contours to keep only large ones
result = img.copy()
for c in contours:
perimeter = cv2.arcLength(c, True)
if perimeter > 200:
cv2.drawContours(result, c, -1, (0,0,255), 1)
# save results
cv2.imwrite("bright_blob_gray.jpg", gray)
cv2.imwrite("bright_blob_edges.jpg", edges)
cv2.imwrite("bright_blob_isotherms.jpg", result)
# show images
cv2.imshow("gray", gray)
cv2.imshow("edges", edges)
cv2.imshow("result", result)
cv2.waitKey(0)
Quantized gray image:
Edge image:
Result:

How to detect a contour or spot on the edge?

I'm trying to detect the black spots on the following image.
I use adaptive thresholding and use find contours in opencv. This method is successful for detecting most of the black spots inside the gray background. However, it's not able to detect the spots on the edges, simply because contour detection thinks the spots are part of the black background, see here:
Here is the code I used to get these contours:
import cv2
image_path = "cropped.png"
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# do adaptive threshold on gray image
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 101, 3)
# apply morphology open then close
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (1, 1))
blob = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10, 10))
blob = cv2.morphologyEx(blob, cv2.MORPH_CLOSE, kernel)
# invert blob
blob = (255 - blob)
# Get contours
cnts, hierarchy = cv2.findContours(blob, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
result1 = img.copy()
cv2.drawContours(result1, cnts, -1, (0, 0, 255), 3)
cv2.imwrite("_Fail_Blob.png", result1)
Any suggestions on how to detect the black spots on the edges? Eventually looking for an algorithm to be able to output sth like the following:
You can use morphological operations for select spot:
By example:
import cv2
fn = 'IdTPp.jpg'
img = cv2.imread(fn)
img=cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
se=cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (45,45))
img2=cv2.morphologyEx(img, cv2.MORPH_CLOSE, se)
img3=cv2.absdiff(img, img2)
cv2.imshow("detected circles", img3)

Detect contours of flies on a white background (sticky trap) that leaves some gray smudges

So i am trying to detect the contours of flies on a white trap, and after to crop these into different photos. But i am getting the contours of smudges on the trap and some flies are not detected.
Also i don't need the green color lines of the trap.
My question is there any way to make sure i get the contours of all the flies and only the files?
code:
image = cv2.imread('test3.jpeg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,100,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(image, contours, -1, (0, 255, 0), 3)
example image
result with current code
Use convert color space to HSV and morphology operations:
import cv2
img1 = cv2.imread('flys.jpg')
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (6,6))
img=cv2.cvtColor(img1, cv2.COLOR_BGR2HSV)
mask=cv2.threshold(img1[:,:,2], 85, 255, cv2.THRESH_BINARY)[1]
mask = cv2.dilate(mask, kernel, iterations = 2)
mask = cv2.erode(mask, kernel, iterations = 7)
mask=cv2.bitwise_not(mask)
output = cv2.connectedComponentsWithStats(mask, 4, cv2.CV_32S)
print('number of flies: ', output[0])
for i in range(1, output[0]):
x,y,w,h,s=output[2][i]
img_crop=img1[y:y+h, x:x+w,:]
cv2.imwrite(str(i)+'_crop_fly.jpg', img_crop)
mask=cv2.cvtColor(mask,cv2.COLOR_GRAY2BGR)
mask[:,:,1]=0
dst = cv2.addWeighted(img1, 0.7, mask, 0.3, 0.0)
cv2.imshow('test', dst)
cv2.imwrite('out_fly.jpg', dst)

how to calculate Asymmetric shapes area in python with opencv

i need to calculate area of Asymmetric shapes like image below
this code read image and convert it to gray and find the shap countour
i need to find out the area of the Asymmetric shapes
import numpy as np
import cv2
# load the image, convert it to grayscale, and blur it slightly
image = cv2.imread("download.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0)
# find contours in the edge map
cnts = cv2.findContours(gray.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(image,cnts, 0, (255, 0, 0), 8)
cv2.imshow("Image", image)
cv2.waitKey(0)
I've tested your code and found that it didn't find contour of the shape. It's because you did cv2.findContours in gray image. The image should be a binary image, so I used cv2.threshold. Then the area can be calculate using cv2.contourArea.
Below is the code and the result.
import numpy as np
import cv2
image = cv2.imread("1.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0)
_,thresh = cv2.threshold(gray,128,255,cv2.THRESH_BINARY_INV)
im, cnts, hier = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for cnt in cnts:
cv2.drawContours(image,cnts, -1, (0, 0, 255), 1)
print(cv2.contourArea(cnt))
cv2.imshow("thresh", thresh)
cv2.imshow("Image", image)
cv2.waitKey(0)
>> 8656.0
>> 3824.5

Categories