Unable to find correct circles with cv2.HoughCircles - python

When I run the code below, I am not able to find consistent circles in the image. The image I am using as input is:
import numpy as np
import matplotlib.pyplot as plt
import cv2
img = cv2.imread("pipe.jpg")
# convert the image to RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# copy the RGB image
cimg = img.copy()
# convert the RGB image to grayscale
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# detect circles using hough transformation
circles = cv2.HoughCircles(image=img, method=cv2.HOUGH_GRADIENT, dp=3,
minDist=60, param1=100, param2=39, maxRadius=200)
for co,i in enumerate(circles[0, :],start=1):
i = [round(num) for num in i]
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
print("Number of circles detected:", co)
plt.imshow(cimg)
plt.show()
The result I get is:

As a pre-processing step, you usually smooth the image prior to the detection. Not smoothing will prompt a lot of false detections. Sometimes you don't see pre-smoothing in some tutorials because the images dealt with have nice clean edges with very little noise. Try using a median blur or Gaussian blur before you perform the detection.
Therefore, try something like:
import cv2
img = cv2.imread("pipe.jpg")
# convert the image to RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# copy the RGB image
cimg = img.copy()
# convert the RGB image to grayscale
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
### NEW - Smooth the image first
blur = cv2.GaussianBlur(img, (5, 5), 0)
# or try
# blur = cv2.medianBlur(img, 5)
# detect circles using hough transformation
circles = cv2.HoughCircles(image=blur, method=cv2.HOUGH_GRADIENT, dp=3,
minDist=60, param1=100, param2=39, maxRadius=200)
Other than that, getting the detection to find all of the circles in the image is subject to playing with the hyperparameters of the Circular Hough Transform and through trial and error.

Related

How can I use thresholding to improve image quality after rotating an image with skimage.transform?

I have the following image:
Initial Image
I am using the following code the rotate the image:
from skimage.transform import rotate
image = cv2.imread('122.png')
rotated = rotate(image,34,cval=1,resize = True)
Once I execute this code, I receive the following image:
Rotated Image
To eliminate the blur on the image, I use the following code to set a threshold. Anything that is not white is turned to black (so the gray spots turn black). The code for that is as follows:
ret, thresh_hold = cv2.threshold(rotated, 0, 100, cv2.THRESH_BINARY)
plt.imshow(thresh_hold)
Instead of getting a nice clear picture, I receive the following:
Choppy Image
Does anyone know what I can do to improve the image quality, or adjust the threshold to create a clearer image?
I attempted to adjust the threshold to different values, but this changed the image to all black or all white.
One way to approach that is to simply antialias the image in Python/OpenCV.
To do that one simply converts to grayscale. Then blurs the image, then applies a stretch of the image.
Adjust the blur sigma to change the antialiasing.
Input:
import cv2
import numpy as np
import skimage.exposure
# load image
img = cv2.imread('122.png')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# blur threshold image
blur = cv2.GaussianBlur(gray, (0,0), sigmaX=2, sigmaY=2, borderType = cv2.BORDER_DEFAULT)
# stretch so that 255 -> 255 and 127.5 -> 0
result = skimage.exposure.rescale_intensity(blur, in_range=(127.5,255), out_range=(0,255)).astype(np.uint8)
# save output
cv2.imwrite('122_antialiased.png', result)
# Display various images to see the steps
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:

OpenCV: Hough Circles, trouble detecting object

I am a complete beginner when it comes to OpenCV, I have no clue where to start when trying to detect circles of a certain size, below is my current code (not much) along with the image I am trying to detect, if anyone could help me or give me some advice it would be much appreciated, (i have converted image to grayscale and added gaussian blur so it is easier to detect) Thanks!
Image
import cv2
import numpy as np
test = cv2.imread('test.jpg')
gray_img = cv2.cvtColor(test, cv2.COLOR_BGR2GRAY)
img = cv2.medianBlur(gray_img, 5)
cimg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.imshow("HoughCirlces", test)
cv2.waitKey()
cv2.destroyAllWindows()
great work, you're almost there, all you have to do now is actually apply the CHT. The function you are looking for is cv2.HoughCircles(). You need to pass the image, in your case you can use either img or cimg and some parameters that might require tuning. Here is some template code
import cv2
import numpy as np
test = cv2.imread('test.jpg')
gray_img = cv2.cvtColor(test, cv2.COLOR_BGR2GRAY)
img = cv2.medianBlur(gray_img, 5)
cimg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,20,
param1=50,param2=30,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv2.imshow("HoughCirlces", test)
cv2.waitKey()
cv2.destroyAllWindows()
You can also take a look at the documentation and tutorial. I'll link them below.
Tutorial: https://docs.opencv.org/4.x/da/d53/tutorial_py_houghcircles.html
Docs: https://docs.opencv.org/4.x/dd/d1a/group__imgproc__feature.html#ga47849c3be0d0406ad3ca45db65a25d2d

Detect vegetation using opencv on satellite images

I am trying to estimate the area of vegetation in square meters on satellite photos, from the colors. I don't have a training dataset, and therefore cannot do machine learning. So I know the results will not be very good, but I try anyway.
To do this, I apply a filter on the colors thanks to cv2.inRange.
import numpy as np
import cv2
img = cv2.imread('staticmap.png')
upperbound = np.array([70, 255,255])
lowerbound = np.array([40, 40,40])
mask = cv2.inRange(img, lowerbound, upperbound)
imask = mask>0
white = np.full_like(img, [255,255,255], np.uint8)
result = np.zeros_like(img, np.uint8)
result[imask] = white[imask]
cv2.imshow(winname = 'satellite image', mat = img)
cv2.imshow('vegetation detection', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
This gives the following results
So it seems that the detection is not too bad.
Now, I would like, from the density of white pixels, detect the areas where there is vegetation and areas where there is not. I imagine an output like this :
Are there any open cv functions that can do this?
You could consider using a Gaussian blur followed by Otsu thresholding like this:
import cv2
# Load image as greyscale
im = cv2.imread('veg.jpg', cv2.IMREAD_GRAYSCALE)
# Apply blur
blur = cv2.GaussianBlur(im,(19,19),0)
# Otsu threshold
_,thr = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

Contours from a image appear very sloppy with cv2 findContours. How to improve?

I'm trying to find the contour of an image using cv2. There are many related questions, but the answer always appear to be very specific and not applicable to my case.
I have an black and white image that I change into color.
thresh = cv2.cvtColor(thresh, cv2.COLOR_RGB2GRAY)
plt.imshow(thresh)
Next, I try to find the contours.
image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
and then I visualize it by plotting it on a black background.
blank_image = np.zeros((thresh.shape[0],thresh.shape[1],3), np.uint8)
img = cv2.drawContours(blank_image, contours, 0, (255,255,255), 3)
plt.imshow(img)
The contour follows the actual contour, i.e. surrounding the whole thing. How do I get something like this very bad paint impression:
You can use Canny edge detection to do this:
import cv2
frame = cv2.imread("iCyrOT3.png") # read a frame
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # turn it gray
edges = cv2.Canny(gray, 100, 200) # get canny edges
cv2.imshow('Test', edges) # display the result
cv2.waitKey(0)

How to uniform the color and texture of a face

I'm trying to cartoonify a face using opencv.Here's the original image
Currently I'm doing
Downscaling the image, applying bifilter and upscaling back to original
Then converting RGB of original image to grayscale and followed
medianblur to reduce nice
Apply Adaptive Threshold to create edgemask
Combining the image obtained from step1 with the edge mask with
bitmap
Here's the output
Then applied non-photorealistic rendering using OpenCV. Here's the final output
I want to generate face with uniform color(remove light reflection as well)without affecting the eyes, mouth. How can I achieve that either by tweaking my current code or another possible approach in opencv(python)
Based on: https://www.pyimagesearch.com/2014/07/07/color-quantization-opencv-using-k-means-clustering/
Here is a code that does what you are looking for:
import cv2
import numpy as np
from sklearn.cluster import MiniBatchKMeans
n = 32
# read image and convert to gray
img = cv2.imread('./obama.jpg',cv2.IMREAD_COLOR)
img = cv2.resize(img, (0,0), fx=.2, fy=.2)
img = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
(h, w) = img.shape[:2]
img =np.reshape(img, (img.shape[0]* img.shape[1], 3))
clt = MiniBatchKMeans(n_clusters=n)
labels = clt.fit_predict(img)
quant = clt.cluster_centers_.astype("uint8")[labels]
quant = np.reshape(quant, (h,w,3))
img = np.reshape(img, (h,w,3))
quant = cv2.cvtColor(quant, cv2.COLOR_LAB2BGR)
img = cv2.cvtColor(img, cv2.COLOR_LAB2BGR)
double = np.hstack([img, quant])
while True:
cv2.imshow('img', double)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
You can use this tutorial to apply the color quantization only to boxes containing faces.
https://realpython.com/face-recognition-with-python/

Categories

Resources