How can ı blur detected object (YoloV5)? [duplicate] - python

I am trying create a circle and blur the contents in OpenCV. However, I am able to make the circle, but I am not able to blur that part. My code is given below. Please help me out
import io
import picamera
import cv2
import numpy as np
import glob
from time import sleep
from PIL import ImageFilter
image = cv2.imread('/home/pi/Desktop/cricle-test/output_0020.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faceCascade = cv2.CascadeClassifier('/home/pi/Desktop/Image-Detection-test/haarcascade_frontalface_alt.xml')
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(30, 30),
flags = cv2.cv.CV_HAAR_SCALE_IMAGE
)
print "Found {0} faces!".format(len(faces))
# Draw a circle around the faces and blur
for (x, y, w, h) in faces:
sub = cv2.circle(image, ( int((x + x + w )/2), int((y + y + h)/2 )), int (h / 2), (0, 255, 0), 5)
cv2.blur(image(x,y,w,h),(23,23), 40000)
cv2.imwrite("/home/pi/Desktop/cricle-test/output_0020.jpg" ,image)

For it to work you need to do a couple of things, first cv2.blur needs a destination and not a number. This can be achieved with:
image[y:y+h, x:x+w] = cv2.blur(image[y:y+h, x:x+w] ,(23,23))
Since you are saving the image to the same file in every loop, you can just save it after the loop.
Since you wanted a circular bur, you need to create a circular mask, then apply it to the image, here is how your code will look like (only the loop part):
# create a temp image and a mask to work on
tempImg = image.copy()
maskShape = (image.shape[0], image.shape[1], 1)
mask = np.full(maskShape, 0, dtype=np.uint8)
# start the face loop
for (x, y, w, h) in faces:
#blur first so that the circle is not blurred
tempImg [y:y+h, x:x+w] = cv2.blur(tempImg [y:y+h, x:x+w] ,(23,23))
# create the circle in the mask and in the tempImg, notice the one in the mask is full
cv2.circle(tempImg , ( int((x + x + w )/2), int((y + y + h)/2 )), int (h / 2), (0, 255, 0), 5)
cv2.circle(mask , ( int((x + x + w )/2), int((y + y + h)/2 )), int (h / 2), (255), -1)
# oustide of the loop, apply the mask and save
mask_inv = cv2.bitwise_not(mask)
img1_bg = cv2.bitwise_and(image,image,mask = mask_inv)
img2_fg = cv2.bitwise_and(tempImg,tempImg,mask = mask)
dst = cv2.add(img1_bg,img2_fg)
cv2.imwrite("/home/pi/Desktop/cricle-test/output_0020.jpg" ,dst)
This seems to work, at least in my test, you may try adjusting the kernel size (this (23,23) in the blur) to get less or more blurred image, for example, try this code with (7,7) it will have more details.
Update
If you want to use ellipses instead of circles just change the circle instruction to:
cv2.ellipse(mask , ( ( int((x + x + w )/2), int((y + y + h)/2 )),(w,h), 0), 255, -1)
The same way you can change it to a rectangle, polygon, or any other shape.

Related

Reliable program that can detect QR Codes without cv2.QRCodeDetector() or pyzbar library

I am having trouble finding a set of morphological operations that allow me to detect (only) the QR codes in various images using cv2.connectedComponentsWithStats() or cv2.findContours() (but I would prefer to solve this with cv2.connectedComponentsWithStats()).
The images I absolutely need the code to work on are the following:
I have been messing with 2 different codes, one using cv2.connectedComponentsWithStats() and the other cv2.findContours() and some other methods (based off nathancy's answer to Detect a QR code from an image and crop using OpenCV). To test I've been using the following codes:
Using cv2.connectedComponentsWithStats(), the problem with this code is that it captures more than the QR code in the 2nd as you can see bellow. In the 1st it works great and in the 3rd as well if scaled to 0.5, or else it also detects more than the QR code like the 2nd image.
import cv2
import numpy as np
#img = cv2.imread('Code-1.jpg'); scale = 1;
img = cv2.imread('Code-2.jpg'); scale = 1;
#img = cv2.imread('Code-3.jpg'); scale = 0.5;
width = int(img.shape[1] * scale); height = int(img.shape[0] * scale); img = cv2.resize(img, (width, height))
og = img.copy()
gray = np.zeros((img.shape[0], img.shape[1]), dtype=np.uint8)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gaussianblur = cv2.GaussianBlur(gray, (7,7), 0)
otsuthresh = cv2.threshold(gaussianblur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
edges = cv2.Canny(otsuthresh, threshold1=100, threshold2=200)
dilate = cv2.dilate(edges,(5,5),iterations=1)
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(dilate, 8, cv2.CV_32S)
for i in range(1,num_labels):
objint = (labels == i).astype(np.uint8)*255/i
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]
area = stats[i, cv2.CC_STAT_AREA]
ratio = w / float(h)
(cX, cY) = centroids[i]
if area > 500 and (ratio > .95 and ratio < 1.05) and (w < 0.99*img.shape[1]):
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
ROI = og[y:y + h, x:x + w]
cv2.imwrite('ROI.png', ROI)
cv2.imshow('image', img)
cv2.imshow('QR code', ROI)
Using cv2.findContours(), this one can't detect any of the QR codes in the images in which the code must not fail, but can detect in some other random images
import cv2
import numpy as np
#img = cv2.imread('Code-1.jpg'); scale = 1;
img = cv2.imread('Code-2.jpg'); scale = 1;
#img = cv2.imread('Code-3.jpg'); scale = 0.5;
width = int(img.shape[1] * scale); height = int(img.shape[0] * scale); img = cv2.resize(img, (width, height))
og = img.copy()
gray = np.zeros((img.shape[0], img.shape[1]), dtype=np.uint8)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gaussianblur = cv2.GaussianBlur(gray, (7,7), 0)
otsuthresh = cv2.threshold(gaussianblur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
closed = cv2.morphologyEx(otsuthresh, cv2.MORPH_CLOSE, kernel, iterations=3)
contours = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if len(contours) == 2:
contours = contours[0]
else:
contours = contours[1]
for cnt in contours:
perim = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.05 * perim, True)
x,y,w,h = cv2.boundingRect(approx)
area = cv2.contourArea(cnt)
ratio = w / float(h)
if len(approx) == 4 and area > 1000 and (ratio > .80 and ratio < 1.2):
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 4)
ROI = og[y:y + h, x:x + w]
cv2.imwrite('ROI.png', ROI)
cv2.imshow('image', img)
cv2.imshow('QR code', ROI)
Thank you for reading and if I wasn't clear on something please let me know.
Filipe Almeida
Maybe, you could try QReader. It is just a wrapper of OpenCV, Pyzbar and other QR detection and image filtering methods, but it works quite out-of-the-box for those cases.
from qreader import QReader
from matplotlib import pyplot as plt
import cv2
if __name__ == '__main__':
# Initialize QReader
detector = QReader()
for img_path in ('0oOAF.jpg', 'HXlS8.jpg', '5fFTo.jpg'):
# Read the image
img = cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2RGB)
# Detect the QR bbox
found, bbox = detector.detect(image=img)
if found:
# Draw the bbox
x1, y1, x2, y2 = bbox
cv2.rectangle(img=img, pt1=(x1, y1), pt2=(x2, y2), color=(0, 255, 0), thickness=2)
# Save the image
plt.imshow(img)
plt.savefig(f"{img_path}-bbox.png")
That's the output it gives:

How can I detect circle by using openCV in python?

I want to detect circle in a picture by using haar cascade. I created an cascade xml.
import cv2
import numpy as np
img = cv2.imread("C://OpenCVcascade//resimler//coins.jpg")
circles_cascade = cv2.CascadeClassifier("C://Cascade//dairetanima.xml")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
circles = circles_cascade.detectMultiScale(gray, 1.1, 1)
if circles is not None:
circles = np.uint16(np.around(circles))
for (x, y, w, h) in circles:
center = (x + w // 2, y + h // 2)
radius = (w + h) // 4
cv2.circle(img, center, radius, (255, 0, 0), 2)
cv2.imshow('image', img)
cv2.waitKey()
cv2.destroyAllWindows()
My result:
I already know, there are different method to detect circle. But I am trying to do with cascade method. Because after this part, I will use it for real time detection.

How to blur a face in opencv with round borders - Python?

I blurred the face in OpenCV like this:
I used this code:
face = cv2.medianBlur(face, 100)
img[top:bottom,left:right] = face
But I want to make the face border round like this (does not need to be perfect)
First, create a mask image. To do so, draw a white circle at the face location on a black image.
Second, blur the whole image.
Third, copy blurred content to the original image only where your mask is > 0.
p1 = (65, 65)
w, h = 100, 100
p2 = (p1[0] + w, p1[1] + h)
circle_center = ((p1[0] + p2[0])// 2, (p1[1] + p2[1]) // 2)
circle_radius = int(math.sqrt(w * w + h * h) // 2)
mask_img = np.zeros(img.shape, dtype='uint8')
cv2.circle(mask_img, circle_center, circle_radius, (255, 255, 255), -1)
img_all_blurred = cv2.medianBlur(img, 99)
img_face_blurred = np.where(mask_img > 0, img_all_blurred, img)
Output:
import cv2
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread('image.jpg')
h, w, c = img.shape
plt.imshow(img)
plt.show()
c_mask = np.zeros((h,w), np.uint8)
cv2.circle(c_mask,(w//2,h//2),100,1,thickness=-1)
mask = cv2.bitwise_and(img, img, mask=c_mask)
plt.imshow(mask)
plt.show()
img_mask = img - mask
plt.imshow(img_mask)
plt.show()
blur = cv2.blur(img,(17, 17))
plt.imshow(blur)
plt.show()
mask2 = cv2.bitwise_and(blur, blur, mask=c_mask) # mask
plt.imshow(mask2)
plt.show()
final_img = img_mask + mask2
print(np.max(final_img))
plt.imshow(final_img)
plt.show()
You can blur whole image then copy the result to source using any mask you like.

findContour() detect unintended internal edges and calculates area wierd for them OpenCV python

I'm not sure what is going on here but when I use the findContours() function using the cv2.RETER_EXTERNAL on this image:
it still seem to detect inside contours and calculates the area of them weirdly which prevents me from filtering the unwanted contours....
Any clue to why is that?
Here is the original and dialated tresh images:
here's the code so far:
import cv2
import PIL
import numpy as np
import imutils
imgAddr = "ADisplay2.jpg"
cropX = 20
cropY = 200
cropAngle = 2
CropIndex = (cropX, cropY, cropAngle)
img = cv2.imread(imgAddr)
cv2.imshow("original image",img)
(h, w) = img.shape[:2]
(cX, cY) = (w / 2, h / 2)
# rotate our image by 45 degrees
M = cv2.getRotationMatrix2D((cX, cY), -1.2, 1.0)
rotated = cv2.warpAffine(img, M, (w, h))
#cv2.imshow("Rotated by 45 Degrees", rotated)
cropedImg = rotated[300:700, 100:1500]
# grab the dimensions of the image and calculate the center of the image
#cv2.imshow("croped img", cropedImg)
grayImg = cv2.cvtColor(cropedImg, cv2.COLOR_BGR2GRAY)
#cv2.imshow("gray scale image", grayImg)
blurredImg = cv2.GaussianBlur(grayImg, (9, 9), 0)
cv2.imshow("Blurred_Img", blurredImg)
(T, threshInvImg) = cv2.threshold(blurredImg, 0, 255,
cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
cv2.imshow("ThresholdInvF.jpg", threshInvImg)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,19))
#opening = cv2.morphologyEx(threshInvImg, cv2.MORPH_OPEN, kernel)
#cv2.imshow("openingImg", opening)
dialeteImg = cv2.morphologyEx(threshInvImg, cv2.MORPH_DILATE, kernel)
cv2.imshow("erodeImg", dialeteImg)
cannyImg = cv2.Canny(dialeteImg, 100,200)
cv2.imshow("Canny_img", cannyImg)
hierarchy,cntsImg,_ = cv2.findContours(cannyImg,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
#print("Img cnts: {}".format(cntsImg))
#print("Img hierarchy: {}".format(hierarchy))
txtOffset = (25, 50)
for cntIdx, cnt in enumerate(cntsImg):
cntArea = cv2.contourArea(cnt)
print("Area of contour #{} = {}".format(cntIdx, cntArea))
(x, y, w, h) = cv2.boundingRect(cnt)
cv2.rectangle(cropedImg, (x, y), (x + w, y + h), (0, 255, 0), 2)
txtIdxPos = [x,y]
txtPos = ((txtIdxPos[0] + txtOffset[0]), (txtIdxPos[1] + txtOffset[1]))
cv2.putText(cropedImg, "#{}".format(cntIdx), txtPos, cv2.FONT_HERSHEY_SIMPLEX, 1.25, (0, 0, 255), 4)
cv2.imshow("drawCntsImg.jpg", cropedImg)
cv2.waitKey(0)
Thanks for helping :D
What you could do is to only use them if they're within a certain size. For this you could use contourArea(). It seems you already compute this anyhow.
For example:
for cntIdx, cnt in enumerate(cntsImg):
cntArea = cv2.contourArea(cnt)
#########################
# Skip iteration if area is too big or small to filter out non-digits
if cntArea < 50 or cntArea > 100: continue # Need to fiddle with these values
#########################
print("Area of contour #{} = {}".format(cntIdx, cntArea))
(x, y, w, h) = cv2.boundingRect(cnt)
cv2.rectangle(cropedImg, (x, y), (x + w, y + h), (0, 255, 0), 2)
txtIdxPos = [x,y]
txtPos = ((txtIdxPos[0] + txtOffset[0]), (txtIdxPos[1] + txtOffset[1]))
cv2.putText(cropedImg, "#{}".format(cntIdx), txtPos, cv2.FONT_HERSHEY_SIMPLEX,1.25, (0, 0, 255), 4)
You are already printing out each contour's area. You could use that to get an idea of what sizes to let through.
If the size digits might vary between images it could still be a problem. For that you could, for example, calculate the average contour area, which should be very close to the typical digit area. Then say that each contour should be at least this close to the average area.
Note: Just remember to make the minimum area large enough to let a 1 through.
Update:
If you want to rather use aspect ratio, then it's easy to change your formula, as you already calculate the height and width.
# If height is smaller than 1.5*w or larger than 2.5*w, then skip
if not 1.5 < h/w < 2.5: continue # Need to fiddle with these values
You could even use this to calculate the area. It has a chance as being different from contourArea. For example:
cntArea = w*h

Blur from OpenCV in Region of Interest

I am trying create a circle and blur the contents in OpenCV. However, I am able to make the circle, but I am not able to blur that part. My code is given below. Please help me out
import io
import picamera
import cv2
import numpy as np
import glob
from time import sleep
from PIL import ImageFilter
image = cv2.imread('/home/pi/Desktop/cricle-test/output_0020.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faceCascade = cv2.CascadeClassifier('/home/pi/Desktop/Image-Detection-test/haarcascade_frontalface_alt.xml')
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(30, 30),
flags = cv2.cv.CV_HAAR_SCALE_IMAGE
)
print "Found {0} faces!".format(len(faces))
# Draw a circle around the faces and blur
for (x, y, w, h) in faces:
sub = cv2.circle(image, ( int((x + x + w )/2), int((y + y + h)/2 )), int (h / 2), (0, 255, 0), 5)
cv2.blur(image(x,y,w,h),(23,23), 40000)
cv2.imwrite("/home/pi/Desktop/cricle-test/output_0020.jpg" ,image)
For it to work you need to do a couple of things, first cv2.blur needs a destination and not a number. This can be achieved with:
image[y:y+h, x:x+w] = cv2.blur(image[y:y+h, x:x+w] ,(23,23))
Since you are saving the image to the same file in every loop, you can just save it after the loop.
Since you wanted a circular bur, you need to create a circular mask, then apply it to the image, here is how your code will look like (only the loop part):
# create a temp image and a mask to work on
tempImg = image.copy()
maskShape = (image.shape[0], image.shape[1], 1)
mask = np.full(maskShape, 0, dtype=np.uint8)
# start the face loop
for (x, y, w, h) in faces:
#blur first so that the circle is not blurred
tempImg [y:y+h, x:x+w] = cv2.blur(tempImg [y:y+h, x:x+w] ,(23,23))
# create the circle in the mask and in the tempImg, notice the one in the mask is full
cv2.circle(tempImg , ( int((x + x + w )/2), int((y + y + h)/2 )), int (h / 2), (0, 255, 0), 5)
cv2.circle(mask , ( int((x + x + w )/2), int((y + y + h)/2 )), int (h / 2), (255), -1)
# oustide of the loop, apply the mask and save
mask_inv = cv2.bitwise_not(mask)
img1_bg = cv2.bitwise_and(image,image,mask = mask_inv)
img2_fg = cv2.bitwise_and(tempImg,tempImg,mask = mask)
dst = cv2.add(img1_bg,img2_fg)
cv2.imwrite("/home/pi/Desktop/cricle-test/output_0020.jpg" ,dst)
This seems to work, at least in my test, you may try adjusting the kernel size (this (23,23) in the blur) to get less or more blurred image, for example, try this code with (7,7) it will have more details.
Update
If you want to use ellipses instead of circles just change the circle instruction to:
cv2.ellipse(mask , ( ( int((x + x + w )/2), int((y + y + h)/2 )),(w,h), 0), 255, -1)
The same way you can change it to a rectangle, polygon, or any other shape.

Categories

Resources