iam trying to apply a heat map on a selected portion[people's face] of my picture. Here is what i had done so far...
the rectangle will be applied to the face .
the face will be cropped
heat map will be applied to the cropped image.
# Draw a rectangle around the faces
for (x, y, w, h) in faces:
cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)
crop_img = image[y:y+h, x:x+w]
# Cropping Area
# Color Mapping Area
images = cv2.imread(crop_img, 0)
colormap = plt.get_cmap('inferno')
heatmap = (colormap(images) * 2**16).astype(np.uint16)[:,:,:3]
heatmap = cv2.cvtColor(heatmap, cv2.COLOR_RGB2BGR)
# Saving Color Map
img_names = "heatimage{}.png".format(i)
cv2.imwrite(img_names, heatmap)
print("{} written!".format(img_names))
img = cv2.imread(img_names,0)
cv2.imshow('heatmap{}'.format(i),heatmap)
i was able to save the cropped image and rectangle pointing faces separately but i need
1. to make the rectangle to be a heat map ,without cropping separately,in my original image.
2. other part of the image has to be normal
EDITED
Draw a rectangle around the faces
for (x, y, w, h) in faces:
cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)
crop_img = image[y:y+h, x:x+w]
sample = cv2.imread("sample.jpg",cv2.COLOR_BGR2GRAY)
colormap = cm.get_cmap('inferno', 256)
cmp = cm.ScalarMappable(cmap='inferno')
# create 1D float gradient from 0 to 1 with 256 increments
# convert to rgba in range 0 to 255 (via bytes=True)
# remove alpha channel and reshape to 256x1 3 channel from (256, 4)
# convert rgb to bgr
cmap = np.linspace(0, 1, 256, endpoint=True)
cmap = cmp.to_rgba(cmap, bytes=True)
cmap = cmap[:, 0:-1].reshape((256, 1, 3))
cmap = cv2.cvtColor(cmap, cv2.COLOR_RGB2BGR)
# apply color map to crop
crop_mapped = cv2.applyColorMap(crop_img, cmap)
# put color mapped crop back into input
result = sample.copy()
result = cv2.cvtColor(result, cv2.COLOR_GRAY2BGR)
result[y:y+h, x:x+w] = crop_mapped
# save result
cv2.imwrite('IRimage.jpg', result)
# show result
cv2.imshow("result", result)
i+=1
cv2.imshow("Faces found", image)
If i have more than one face , how can i apply color filter to both the faces?
If I understand correctly, you're trying to display the portion of a heatmap that's on the face of a person.Try this
alpha = 0.5
image[y:y+h, x:x+w] = alpha * image[y:y+h, x:x+w] + (1 - alpha) * heatmap[y:y+h, x:x+w]
cv2.imshow("preview", image)
I believe that you will have to crop the image, apply the colormap to the cropped image, then put the color mapped crop image back into your original. I do not think there is a way to apply a colormap directly to a portion of an image.
Here is how I do the above in Python/OpenCV.
Read the input as grayscale
Crop the image where you want it to be color mapped
Load the colormap from Matplotlib and convert it to a BGR image
Apply the colormap to the cropped image
Convert the input to 3 channel gray and insert the color mapped cropped image back in the correct location.
Save the results
Input:
import cv2
import numpy as np
import matplotlib.cm as cm
# read image and convert to gray
img = cv2.imread('redhat_gray.jpg', cv2.COLOR_BGR2GRAY)
# crop image
crop = img[140:240, 70:170]
# get colormap from matplotlib and normalize
colormap = cm.get_cmap('inferno', 256)
cmp = cm.ScalarMappable(cmap='inferno')
# create 1D float gradient from 0 to 1 with 256 increments
# convert to rgba in range 0 to 255 (via bytes=True)
# remove alpha channel and reshape to 256x1 3 channel from (256, 4)
# convert rgb to bgr
cmap = np.linspace(0, 1, 256, endpoint=True)
cmap = cmp.to_rgba(cmap, bytes=True)
cmap = cmap[:, 0:-1].reshape((256, 1, 3))
cmap = cv2.cvtColor(cmap, cv2.COLOR_RGB2BGR)
#print(cmap)
# apply color map to crop
crop_mapped = cv2.applyColorMap(crop, cmap)
# put color mapped crop back into input
result = img.copy()
result = cv2.cvtColor(result, cv2.COLOR_GRAY2BGR)
result[140:240, 70:170] = crop_mapped
# save result
cv2.imwrite('redhat_gray_rectangle_inferno.jpg', result)
# show result
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
Related
I tried to mask image by its color using opencv.
import cv2
import numpy as np
import matplotlib.pyplot as plt
After importing libraries, I load the image
img = cv2.imread('gmaps.jpg')
image = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
plt.imshow(image);
Turn the color into hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
plt.imshow(hsv);
Masking process
low_orange = np.array([44, 6, 100])
high_orange = np.array([44, 24, 99])
masking = cv2.inRange(hsv,low_orange, high_orange)
plt.imshow(masking);
The result isn't what I expected.
Image :
Result :
EDIT: I want to mask the building only. Instead I got the result of masking all of the frame.
Using my answer from here I manage to extract the right values for you
Code:
frame = cv2.imread("Xv6gx.png")
blurred_frame = cv2.GaussianBlur(frame, (5, 5), 0)
hsv = cv2.cvtColor(blurred_frame, cv2.COLOR_BGR2HSV)
lower = np.array([4, 0, 7])
upper = np.array([87, 240, 255])
mask = cv2.inRange(hsv, lower, upper)
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
for contour in contours:
area = cv2.contourArea(contour)
if area > 5000:
# -- Draw Option 1 --
cv2.drawContours(frame, contour, -1, (0, 255, 0), 3)
# -- Draw Option 2--
# rect = cv2.boundingRect(contour)
# x, y, w, h = rect
# cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow("Mask", mask)
cv2.imshow("Frame", frame)
cv2.waitKey(0)
Final Results:
I wouldn't expect the low Value (100) to exceed the high Value (99).
Also, OpenCV uses a range of 0..180 for Hue rather than 0..360, so you likely need to divide your 44 by 2.
I have to crop a lot of images manually. Not the funniest thing to do. So I thought I'd try to do it using Python.
I can detect the subject, create a mask, but I have no idea how to get the points from the very bottom part and crop based on them.
Any help is appreciated
import cv2
img = cv2.imread('image5.jpg')
h, w = img.shape[:2]
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thr = cv2.threshold(gray, 192, 255, cv2.THRESH_BINARY_INV)[1]
cv2.imwrite('result5.png', thr)
you can try to find all external contours using cv2.RETR_EXTERNAL and pick the bottom most point, like this:
import cv2
import numpy as np
import imutils
im = cv2.imread('images/tennis.jpg')
# Percent of original size
scale_percent = 20
width = int(im.shape[1] * scale_percent / 100)
height = int(im.shape[0] * scale_percent / 100)
dim = (width, height)
# Resize image
im = cv2.resize(im, dim, interpolation = cv2.INTER_AREA)
# Convert to grayscale
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# Canny
canny_output = cv2.Canny(im, 120, 240)
# Find external contours
contours, hierarchy = cv2.findContours(canny_output, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
#cv2.drawContours(im, [contours[0]], 0, (0,255,0), 3) # Uncomment this line to see what contour opencv is finding
# Pick the bottom most point and add an offset (whatever value you want, this is just for aesthetics)
c = contours[0]
bottommost = tuple(c[c[:, :, 1].argmax()][0])[1] + 5
# Crop image
im = im[:bottommost, :]
# Show image
cv2.imshow('image', im)
cv2.waitKey()
Very good thinking I'd say! now the implementation:
xx,yy = thrs.nonzero()
max_crop_h = xx.max()
crop = img[:max_crop_h,:]
numpy has your back!
I am new to StackOverflow.
I am trying to detecting shapes as per names and shapes in image of diamonds.various shapes of diamond. For shape detection purpose I used the program given at https://www.pyimagesearch.com/2016/02/08/opencv-shape-detection/
Here is the code:
import cv2
import imutils
class ShapeDetector:
def __init__(self):
pass
def detect(self, c):
# initialize the shape name and approximate the contour
shape = "unidentified"
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.04 * peri, True)
# if the shape is a triangle, it will have 3 vertices
if len(approx) == 3:
shape = "triangle"
# if the shape has 4 vertices, it is either a square or
# a rectangle
elif len(approx) == 4:
# compute the bounding box of the contour and use the
# bounding box to compute the aspect ratio
(x, y, w, h) = cv2.boundingRect(approx)
ar = w / float(h)
# a square will have an aspect ratio that is approximately
# equal to one, otherwise, the shape is a rectangle
shape = "square" if ar >= 0.95 and ar <= 1.05 else "rectangle"
# if the shape is a pentagon, it will have 5 vertices
elif len(approx) == 5:
shape = "pentagon"
# otherwise, we assume the shape is a circle
else:
shape = "circle"
# return the name of the shape
return shape
# -----------------
image = cv2.imread(shape_image)
resized = imutils.resize(image, width=300)
ratio = image.shape[0] / float(resized.shape[0])
gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.threshold(blurred, 20, 255, cv2.THRESH_BINARY)[1]
# find contours in the thresholded image and initialize the
# shape detector
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
sd = ShapeDetector()
# loop over the contours
for c in cnts:
# compute the center of the contour, then detect the name of the
# shape using only the contour
M = cv2.moments(c)
cX = int((M["m10"] / M["m00"]) * ratio)
cY = int((M["m01"] / M["m00"]) * ratio)
shape = sd.detect(c)
# multiply the contour (x, y)-coordinates by the resize ratio,
# then draw the contours and the name of the shape on the image
c = c.astype("float")
c *= ratio
c = c.astype("int")
cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
cv2.putText(image, shape, (cX, cY), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
print("The Shape of Object is: ", shape)
# show the output image
cv2.imshow("Image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
But, I am unable to get perfect results for that. Is there any way to find out shapes like which are given in image.
from the discussion : Crop exactly document paper from image
I'm trying to get the white paper from the image and I'm using the following code which not cropping exactly rectangular.
def crop_image(image):
image = cv2.imread(image)
# convert to grayscale image
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# threshold
thresh = cv2.threshold(gray, 190, 255, cv2.THRESH_BINARY)[1]
# apply morphology
kernel = np.ones((7, 7), np.uint8)
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
kernel = np.ones((9, 9), np.uint8)
morph = cv2.morphologyEx(morph, cv2.MORPH_ERODE, kernel)
# Get Largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contours = contours[0] if len(contours) == 2 else contours[1]
area_thresh = 0
for cnt in contours:
area = cv2.contourArea(cnt)
if area > area_thresh:
area_thresh = area
big_contour = cnt
# get bounding box
x, y, w, h = cv2.boundingRect(big_contour)
# draw filled contour on black background
mask = np.zeros_like(gray)
mask = cv2.merge([mask, mask, mask])
cv2.drawContours(mask, [big_contour], -1, (255, 255, 255), cv2.FILLED)
# apply mask to input
result = image.copy()
result = cv2.bitwise_and(result, mask)
# crop result
img_result = result[y:y+h, x:x+w]
filename = generate_filename()
cv2.imwrite(filename, img_result)
logger.info('Successfully saved cropped file : %s' % filename)
return img_result, filename
I'm able to get the desired result but not the rectangular image.
Here I'm attaching and here is what I'm getting after cropping image .
I want a rectangular image of the paper.
Please help me with this.
Thanks in advance
The first problem I can see is that the threshold value is not low enough so the bottom part of the paper is not correctly capture (it's too dark to be captured by the threshold)
The second problem as far I can understand is being able to fit the square to the image. What you need to do is wrapping perspective.
To do that you can find more information in this amazing post of PyImageSearch
I need to crop an image for further processing on it using opencv and python. I need to crop the region inside the green colored rectangle in the image. The rectangle is drawn using "haar_cascade_fullbody_Detector"
The code is as follows :
import numpy as np
import cv2
bodydetection = cv2.CascadeClassifier('haarcascade_fullbody.xml')
img = cv2.imread('original.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
body = bodydetection.detectMultiScale(gray, 1.009, 5)
for x, y, w, h in body:
# so we slightly shrink the rectangles to get a nicer output.
pad_w, pad_h = int(0.15*w), int(0.02*h)
cv2.rectangle(img, (x+pad_w+10, y+pad_h+10), (x+w-pad_w, y+h-pad_h), (0, 255, 0), 2)
cv2.imshow('img',img)
crop_img = img[x:x+w, y:y+h]
cv2.imshow('crop',crop_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
The input image is :
The output of haar cascade is :
after the crop the image is :
Please suggest any solution. Thanks!
Ok! I got the answer. The line of crop_img should be modified as
crop_img = img[y:y+h, x:x+w]
This produces required output.This is because in opencv the img coordinated sequence is y-coordinates and then x-coordinates.