OpenCV: Hough Circles, trouble detecting object - python

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

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:

Removing the noise in edge detection

I was trying the detect and extract an image from the background (Example image here). Used canny edge detection and Hough transform for lines detection. But I'm getting wrong result due to noise in the image. An example image (Intermediate result) is shown here. Kindly help me to solve this problem in python.
I have used technique from below site and in addition to this used idea of Hough transform.
https://www.pyimagesearch.com/2014/04/21/building-pokedex-python-finding-game-boy-screen-step-4-6/
I hope this helps you:
import cv2
img = cv2.imread('image.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)[:, :, 2]
kern_size = 11
gray_blurred = cv2.medianBlur(gray, kern_size)
threshold_lower = 30
threshold_upper = 220
edged = cv2.Canny(gray_blurred, threshold_lower, threshold_upper)
cv2.imshow('edged',edged)
cv2.waitKey(0)

Unable to find correct circles with cv2.HoughCircles

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.

Processing image for reducing noise with OpenCV in Python

I want to apply some kind of preprocessing to this image so that text can be more readable, so that later I can read text from image. I'm new to this so I do not know what should I do, should I increase contrast or should I reduce noise, or something else. Basically, I want to remove these gray areas on the image and keep only black letters (as clear as they can be) and white background.
import cv2
img = cv2.imread('slika1.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow('gray', img)
cv2.waitKey(0)
thresh = 200
img = cv2.threshold(img, thresh, 255, cv2.THRESH_BINARY)[1]
cv2.imshow('filter',img)
cv2.waitKey(0)
I read the image and applied threshold to the image but I needed to try 20 different thresholds until I found one that gives results.
Is there any better way to solve problems like this?
The problem is that I can get different pictures with different size of gray areas, so sometime I do not need to apply any kind of threshold, and sometimes I do, because of that I think that my solution with threshold is not that good.
For this image, my code works good:
But for this it gives terrible results:
Try division normalization in Python/OpenCV. Divide the input by its blurred copy. Then sharpen. You may want to crop the receipt better or mask out the background first.
Input:
import cv2
import numpy as np
import skimage.filters as filters
# read the image
img = cv2.imread('receipt2.jpg')
# convert to gray
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# blur
smooth = cv2.GaussianBlur(gray, (95,95), 0)
# divide gray by morphology image
division = cv2.divide(gray, smooth, scale=255)
# sharpen using unsharp masking
sharp = filters.unsharp_mask(division, radius=1.5, amount=1.5, multichannel=False, preserve_range=False)
sharp = (255*sharp).clip(0,255).astype(np.uint8)
# save results
cv2.imwrite('receipt2_division.png',division)
cv2.imwrite('receipt2_division_sharp.png',sharp)
# show results
cv2.imshow('smooth', smooth)
cv2.imshow('division', division)
cv2.imshow('sharp', sharp)
cv2.waitKey(0)
cv2.destroyAllWindows()
Division result:
Sharpened result:

Is there any function for cropping the binary image in opencv or other packages?

I'm just working on images and I found difficult on cropping the binary images automatically. I'm new to Image processing.
Example images are shown below,
Original image:
Needed output(manually edited by GIMP Image editor):
I needed to crop the image by finding the edges of a whit pixels(mask) in image. But its hard to find the approximate edges. Please help me to find out.
thanks in advance..!
You can use findContours to find the bounding of the object, then use minAreaRect to draw your needed output, 1st image. Or you can just draw the bounding of the object, 2nd image.
import cv2
import numpy as np
img = cv2.imread('1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_,thresh = cv2.threshold(gray,128,255,cv2.THRESH_BINARY)
_,contours,_ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
mask = np.zeros(img.shape)
cv2.drawContours(mask, contours, -1 , (255,255,255), 1)
rect = cv2.minAreaRect(contours[0])
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(img,[box],0,(255,255,255),1)
cv2.imshow("img",img)
cv2.imshow("mask",mask)
cv2.waitKey(0)
cv2.destroyAllWindows()

Categories

Resources