openCV face detection - python

This is a simple code for face detection using openCV :
import cv2
img = cv2.imread("one.jpg")
hc = cv2.CascadeClassifier("haarcascade_frontalface_alt2.xml")
faces = hc.detectMultiScale(img)
for face in faces:
print 'inside for loop ! '
cv2.rectangle(img, (face[0], face[1]), (face[0] + face[2], face[0] + face[3]), (255, 0, 0), 3)
cv2.imshow("Face", img)
if cv2.waitKey(5000) == 27:
cv2.destroyWindow("Face")
cv2.imwrite("two.jpg", img)
but when I run this code, the final image displayed ie two.jpg is the same as given in input ie one.jpg! without any face being detected.. the code inside the for loop is never executed ... why is it so ? Are there any changes which I should make in the code ?
this is the image I am giving as one.jpg & the final image ie two.jpg also looks the same

It seems none of the faces in the image you use have been detected (in which case, the for loop will not be executed). you can:
Use an image that has an easier-to-detect (large, no glasses) face.
Step through the code using a debugger (I don't know how to do this in Python, but it should be easier to find out)
Check the following attributes of faces
a. size
b. location coordinates of each face if detected.

Related

Finding Loss Between Saliency Maps

I'm currently working on a style transfer project and wanted to look at the difference between the salience maps of the content and style image. I've managed to get the actual transfer working but am having issues trying to workout how to minimize the saliency loss between 2 images. The code below is the one used to generate the salience maps.
import cv2
imgpath = r'Content Image.jpg'
image = cv2.imread(imgpath)
saliency = cv2.saliency.StaticSaliencySpectralResidual_create()
(success, saliencyMap) = saliency.computeSaliency(image)
saliencyMap = (saliencyMap * 255).astype("uint8")
cv2.imshow("Image", image)
cv2.imshow("Output", saliencyMap)
cv2.waitKey(0)
cv2.destroyAllWindows()
imgpath = r'Content Image.jpg'
image = cv2.imread(imgpath)
saliency = cv2.saliency.StaticSaliencyFineGrained_create()
(success, saliencyMap) = saliency.computeSaliency(image)
# Set threshold for saliency map
threshMap = cv2.threshold(saliencyMap.astype("uint8"), 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("Image", image)
cv2.imshow("Output", saliencyMap)
# cv2.imshow("Thresh", threshMap)
cv2.waitKey(0)
The pictures below are the result of running the above code except the Content Image is replace with 'Style Image'. I can see that the map is working fine, however, I have been struggling on how to work out how to get a value for the salience map or how to subtract one from the other in order to see what the difference is between the 2 if that makes sense.
So my question is, is there a way to compute the numerical difference between the 2 maps? I am looking to minimize this "difference" between the 2 maps but have not figured out how to do it.
Thanks
The issue I had was to make sure that both are the same size and then you can do an absolute difference.
z = cv2.absdiff(g,l)
This gives the resultant difference between the 2.

Is there a simple way to map a texture to a different "UV" system in python?

I really don't know if "UV's" is the right word as i'm from the world of Unity and am trying to write some stuff in python. What i'm trying to do is to take a picture of a human (from webcam) take the placement of their landmarks/key features and alter a second image (of a different person) to make their key features in the same place whilst morphing / warping the parts of their skin that are within the face to fit the position of the first input image (webcam)'s landmarks. After i do that I need to put the face back on the non-webcam input. (i'm sorry for how much that made me sound like a serial killer, stretching and cutting faces) I know that probably didn't make any sense but I want it to look like this.
I have the face landmark and cutting done with DLIB and OpenCV but i need a way to find a way to take these "cut" face chunks and stretch them "dynamically". What I mean by dynamically is that you don't just put a mask on by linearly re-sizing it on 1 or 2 axises. You can select a point of the mask and change that, I wanna do that but my mask is my cut chunk and the point is a section of that chunk that needs to change for the chunk to comply with the position of the generated landmarks. I know this is a very hard topic to think about and if you guys need any clarification just ask. My code:
import cv2
import numpy as np
import dlib
cap = cv2.VideoCapture(0)
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
while True:
_, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = detector(gray)
for face in faces:
x1 = face.left()
y1 = face.top()
x2 = face.right()
y2 = face.bottom()
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 3)
landmarks = predictor(gray, face)
for n in range(0, 68):
x = landmarks.part(n).x
y = landmarks.part(n).y
cv2.circle(frame, (x, y), 4, (255, 0, 0), -1)
cv2.imshow("Frame", frame)
key = cv2.waitKey(1)
if key == 27:
break
EDIT: No i'm not a serial killer
If you need to deform source image like a rubber sheet using 2 sets of keypoints, you need to use thin plate spline (TPS), or, better, piecewice affine transformation like here. The last one is more similar to texture rasterization methods (triangle to triangle texture transform).

I want to increase brightness and contrast of images in dynamic way so that the program is applicable for any new images

I have few images where I need to increase or decrease the contrast and brightness of the image in a dynamic way so that it is visible clearly. And the program needs to be dynamic so that it even works for new images also. I also want character should be dark.
I was able to increase brightness and contrast but it is not working properly for each image.
import cv2
import numpy as np
img = cv2.imread('D:\Bright.png')
image = cv2.GaussianBlur(img, (5, 5), 0)
#image = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY)[1]
#kernel = np.ones((2,1),np.uint8)
#dilation = cv2.dilate(img,kernel)
cv2.imshow('test', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
imghsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
imghsv[:,:,2] = [[max(pixel - 25, 0) if pixel < 190 else min(pixel + 25, 255) for pixel in row] for row in imghsv[:,:,2]]
cv2.imshow('contrast', cv2.cvtColor(imghsv, cv2.COLOR_HSV2BGR))
#cv2.imwrite('D:\\112.png',cv2.cvtColor(imghsv, cv2.COLOR_HSV2BGR))
cv2.waitKey(0)
cv2.destroyAllWindows()
#raw_input()
I want a program which works fine for every image and words are a little darker so that they are easily visible.
As Tilarion suggested, you could try "Auto Brightness And Contrast" to see if it works well. The theory behind this is explained well here in the solution section. The solution is in C++. I've written a version of it in python which you can directly use, works only on 1 channel at a time for colour images:
def auto_brightandcontrast(input_img, channel, clip_percent=1):
histSize=180
alpha=0
beta=0
minGray=0
maxGray=0
accumulator=[]
if(clip_percent==0):
#min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(hist)
return input_img
else:
hist = cv2.calcHist([input_img],[channel],None,[256],[0, 256])
accumulator.insert(0,hist[0])
for i in range(1,histSize):
accumulator.insert(i,accumulator[i-1]+hist[i])
maxx=accumulator[histSize-1]
minGray=0
clip_percent=clip_percent*(maxx/100.0)
clip_percent=clip_percent/2.0
while(accumulator[minGray]<clip_percent[0]):
minGray=minGray+1
maxGray=histSize-1
while(accumulator[maxGray]>=(maxx-clip_percent[0])):
maxGray=maxGray-1
inputRange=maxGray-minGray
alpha=(histSize-1)/inputRange
beta=-minGray*alpha
out_img=input_img.copy()
cv2.convertScaleAbs(input_img,out_img,alpha,beta)
return out_img
It is a very few lines of code to do it in Python Wand (which is based upon ImageMagick). Here is a script.
#!/bin/python3.7
from wand.image import Image
with Image(filename='task4.jpg') as img:
img.contrast_stretch(black_point=0.02, white_point=0.99)
img.save(filename='task4_stretch2_99.jpg')
Input:
Result:
Increase the black point value to make the text darker and/or decrease the white point value to make the lighter parts brighter.
Thanks to Eric McConville (the Wand developer) for correcting my arguments to make the code work.

detect patternts and digits in image with openCV and python

I am trying to create a program that can input an image (I am doing it by imageGrab from PIL) and detect some known symbols in it, and their locations. The good thing is that I am pretty sure I don't need neural networks, because I know the exact shape and size of each symbol. the problem is that I have no idea how much of these will be, and what is the color in the background of each symbol. some of the symbols are numbers, I have an image of each digit 0-9, but there may be up to 3-digit numbers. I think I will be able to find a way to know which digits are part of the same number by their location, but lets talk about it later. right now, I have turned the image into grayscale and imshow it using opencv2.
do you have any idea how can I do it with opencv? some other library?
and I need it to be fast enough, hopefuly 10 frames per second.
this is my current code (modified sentdex's "python plays GTA" code, the most bottom of the page):
import numpy as np
from PIL import ImageGrab
import cv2
def screen_record():
while(True):
global printscreen
image = ImageGrab.grab(bbox=(20,270,430,685))
printscreen = np.array(image)
grayscale_image = cv2.cvtColor(printscreen, cv2.COLOR_BGR2GRAY)
cv2.imshow('window', grayscale_image)
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
if cv2.waitKey(25) & 0xFF == ord('w'):
image.save("screen_shot.png")
print("Saved current window as image")
screen_record()
EDIT: I managed to get to something with opencv's template match, only with the digit 2 (for now). I found a nice tutorial here. my problem is when there is not exactly 1 match of the template, means no number 2s, or more then 1. when there aren't any it looks like its choosing something random on the image, and when there's more then one, I have only 1 of them detected. is it ossible to apply it in a different way to match my needs?
So, I have a solution to my problem.
For all of those who reach this page in the future to get help, here are the steps to regognize templates in images:
create 2 images, the one you want to detect, and another one for your template.
then, upload the whoever you want using opencv, and copy this function:
def locate_symbol(x, template):
w, h = filter_num2.shape[::-1]
res = cv2.matchTemplate(x, template, cv2.TM_SQDIFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
min_thresh = 0.45
match_locations = np.where(res<=min_thresh)
return w, h, match_locations
and use these lines to draw bounding boxes on the image:
w, h, locs = locate_symbol(grayscale_image, filter_num2)
for (x, y) in zip(locs[1], locs[0]):
cv2.rectangle(printable_image, (x, y), (x+w, y+h), [255, 0, 0], 2)
then you can draw everything with cv2.imshow()

rectangle not showing up in opencv

Why is rectangle not showing up in my code?
import cv2
im = cv2.imread('players.bmp')
#im.shape >>returns (765,1365,3)
cv2.rectangle(im, (64,1248), (191,1311), (0,255,0), 2)
cv2.namedWindow("image", cv2.WINDOW_NORMAL)
cv2.imshow('image', im)
cv2.waitKey(0)
cv2.destroyAllWindows()
I had a completely different cause for the issue
for me it wasn't showing up because I was using a numpy view from the image, so instead of using cv2.cvtColor(frame, cv2.COLOR_RGB2BGR), I instead used frame[..., ::-1] to convert RGB and BGR.
Somehow this makes the result immutable and when cv2.rectangle tries to write to it, it just doesn't get changed.
It does not show the rectangle, because you are drawing it outside the image.
Why? you may be asking. It is simple. You have this:
#im.shape >>returns (765,1365,3)
This means
rows/height = 765
cols/width = 1365
channels = 3
Then you do
cv2.rectangle(im, (64,1248), (191,1311), (0,255,0), 2)
Here you use 2 points which are tuples (x,y), but you are writing them as if they where tuples (y,x). I know that OpenCV uses in a lot of functions the order (y,x), but this is due that they see the image as a matrix, which commonly is accessed with (row, column) which translates to (y,x). In the case of this rectangle they require Points which are expressed in the typical Cartesian way (x,y).
In conclusion, just change it to:
cv2.rectangle(im, (1248, 64), (1311, 191), (0,255,0), 2)
And it should work.
I stumbled upon this question while facing the same problem. In my case, I was correctly passing x and y along with x+w and y+h. I had made 2 mistakes though:
I had this part in a try and except block (so I couldn't see the exception being raised)
My code was changing h to an array prior to me drawing the rectangle. (I had extracted the values of x,y,w,h from x,y,w,h = cv2.boundingRect(cnt) before mistakenly changing h to [1,-1,-1,-1])

Categories