Extracted Facial Region using DLIB contain noise - opencv

Greeting,
I have been trying to extract some regions from the face
In this case (upper lip) using Dlib, the thing is after extracting the ROI (which look perfect) I realized that there is some noise around the ROI
Can't figure out what I'm doing wrong, and how to resolve this issue.
This is the used Python code:
import cv2
import numpy as np
import dlib
import os
from scipy import ndimage, misc
import time
def extract_index_nparray(nparray):
index = None
for num in nparray[0]:
index = num
break
return index
img = cv2.imread( 'input_facial_image.jpg')
img=cv2.resize(img,(512,512))
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
mask = np.zeros_like(img_gray)
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("/facial-landmarks-recognition/shape_predictor_68_face_landmarks.dat")
# Face 1
faces = detector(img_gray)
for face in faces:
landmarks = predictor(img_gray, face)
landmarks_points = []
for n in [48,49,50,51,52,53,54,64,63,62,61,60]:
x = landmarks.part(n).x
y = landmarks.part(n).y
landmarks_points.append((x, y))
points = np.array(landmarks_points, np.int32)
convexhull = cv2.convexHull(points)
# cv2.polylines(img, [convexhull], True, (255, 0, 0), 3)
cv2.fillConvexPoly(mask, convexhull, 255)
face_image_1 = cv2.bitwise_or(img, img, mask=mask)
cv2.imwrite('extracted_lips.jpg', face_image_1 )
The extracted image looks like this :
upper lips extracted image
But in further steps in my work, I realized a noise around the upper lip, so I examined and I found unclean_upperlip
Is there any way to get rid of the noise during the ROI extracting or any image processing technique to bypass this issue?
Thanks in advance

For anyone who faced the same issue as me, it's simple. Just change the output format to png. The JPG compressing is the issue here.
I hope that this helps

Related

OpenCV Sift - keypoints detects centroid of object?

I am trying to find centroid of circular shape with the help of OpenCV Sift for my project.
After finding centroid try to fit a encoding ring to detect type of marker. The SIFT algorithm is the best for my project, since it is scalar and rotation invariant. It seems to detect the keypoint of centroid of object and i am trying to get the coordinates of it.
import cv2
import numpy as np
def findSift(img, gray, draw=True):
sift = cv2.SIFT_create(10)
kp = sift.detect(gray, None)
if draw:
cv2.drawKeypoints(img, kp, img)
kp_coordinates = cv2.KeyPoint_convert(kp)
return kp_coordinates
if __name__ == "__main__":
img = cv2.imread('Test.jpg')
print(img.shape[:2])
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
Array_Cooridinates = findSift(img,gray)
cv2.imshow('img',img)
cv2.waitKey(0)
Image Resolution: (849, 734)
Array of coordinates of keypoints detected:
[[346.20126 385.5532 ]
[366.1102 217.0911 ]
[366.1102 217.0911 ]
[482.2291 451.484 ]
[482.2291 451.484 ]
[468.70483 303.86118]
[468.70483 303.86118]
[385.93945 296.0943 ]
[417.37436 445.36234]
[441.80768 377.35934]]
If someone have any reference to my problem, feel free to post it so i can do more research about it.
Thanks for any help here!
Have a nice day.

How to crop the given Irregularly shaped object along its outline in OpenCV

I have been working on a code where an image is given as shown
I have to place this knife onto some other image. The condition is that I have to crop the knife along its outline and not in a rectangular box.
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('2.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)
img_blur = cv2.bilateralFilter(img, d = 7,
sigmaSpace = 75, sigmaColor =75)
img_gray = cv2.cvtColor(img_blur, cv2.COLOR_RGB2GRAY)
a = img_gray.max()
_, thresh = cv2.threshold(img_gray, a/2+60, a,cv2.THRESH_BINARY_INV)
plt.imshow(thresh, cmap = 'gray')
contours, hierarchy = cv2.findContours(
image = thresh,
mode = cv2.RETR_TREE,
method = cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key = cv2.contourArea, reverse = True)
img_copy = img.copy()
final = cv2.drawContours(img_copy, contours, contourIdx = -1,
color = (255, 0, 0), thickness = 2)
plt.imshow(img_copy)
This is what I have tried but it doesn't seem to work well.
Input
Output
You can do it starting with bounding box using snake algorithm with balloon force added.
Snake's algo is defined such that it minimizes 3 energies - Continuity, Curvature and Gradient. The first two (together called internal energy) get minimized when points (on curve) are pulled closer and closer i.e. contract. If they expand then energy increases which is not allowed by snake algorithm.
But this initial algo proposed in 1987 has a few problems. One of the problem is that in flat areas (where gradient is zero) algo fails to converge and does nothing. There are several modifications proposed to solve this problem. The solution of interest here is - Balloon Force proposed by LD Cohen in 1989.
Balloon force guides the contour in non-informative areas of the image, i.e., areas where the gradient of the image is too small to push the contour towards a border. A negative value will shrink the contour, while a positive value will expand the contour in these areas. Setting this to zero will disable the balloon force.
Another improvement is - Morphological Snakes which use morphological operators (such as dilation or erosion) over a binary array instead of solving PDEs over a floating point array, which is the standard approach for active contours. This makes Morphological Snakes faster and numerically more stable than their traditional counterpart.
Scikit-image's implementation using the above two improvements is morphological_geodesic_active_contour. It has a parameter balloon
Using your image
import numpy as np
import matplotlib.pyplot as plt
from skimage.segmentation import morphological_geodesic_active_contour, inverse_gaussian_gradient
from skimage.color import rgb2gray
from skimage.util import img_as_float
from PIL import Image, ImageDraw
im = Image.open('knife.jpg')
im = np.array(im)
im = rgb2gray(im)
im = img_as_float(im)
plt.imshow(im, cmap='gray')
Now let us create a function which will help us to store iterations:
def store_evolution_in(lst):
"""Returns a callback function to store the evolution of the level sets in
the given list.
"""
def _store(x):
lst.append(np.copy(x))
return _store
This method needs image to be preprocessed to highlight the contours. This can be done using the function inverse_gaussian_gradient, although the user might want to define their own version. The quality of the MorphGAC segmentation depends greatly on this preprocessing step.
gimage = inverse_gaussian_gradient(im)
Below we define our starting point - a bounding box.
init_ls = np.zeros(im.shape, dtype=np.int8)
init_ls[200:-400, 20:-30] = 1
List with intermediate results for plotting the evolution
evolution = []
callback = store_evolution_in(evolution)
Now required magic line for morphological_geodesic_active_contour with balloon contraction is below:
ls = morphological_geodesic_active_contour(gimage, 200, init_ls,
smoothing=1, balloon=-0.75,
threshold=0.7,
iter_callback=callback)
Now let us plot the results:
fig, axes = plt.subplots(1, 2, figsize=(8, 8))
ax = axes.flatten()
ax[0].imshow(im, cmap="gray")
ax[0].set_axis_off()
ax[0].contour(ls, [0.5], colors='b')
ax[0].set_title("Morphological GAC segmentation", fontsize=12)
ax[1].imshow(ls, cmap="gray")
ax[1].set_axis_off()
contour = ax[1].contour(evolution[0], [0.5], colors='r')
contour.collections[0].set_label("Starting Contour")
contour = ax[1].contour(evolution[25], [0.5], colors='g')
contour.collections[0].set_label("Iteration 25")
contour = ax[1].contour(evolution[-1], [0.5], colors='b')
contour.collections[0].set_label("Last Iteration")
ax[1].legend(loc="upper right")
title = "Morphological GAC Curve evolution"
ax[1].set_title(title, fontsize=12)
plt.show()
With more balloon force you can get only the blade of knife as well.
ls = morphological_geodesic_active_contour(gimage, 100, init_ls,
smoothing=1, balloon=-1,
threshold=0.7,
iter_callback=callback)
Play with these parameters - smoothing, balloon, threshold to get your perfect curve

How to get single lines/curves for edges?

This is my first experience with image processing. In the jupiter notebook, using scipy , I am trying to convert a gray scale line art image into SVG vector representation. So far I was able to convert the gray scale image to binary (monochrome image) and use sobel filter in x and y axis to get the edges of the drawing. I am getting double lines as edges to account for the both sides of the lines (as shown in below picture and also the code i have used)
I want to replace these double lines with a single one. After that to detect the lines and curves in the drawing and convert them to svg lines and bezier curves. Searching online, i am getting a bit overwhelmed and confused about the proper way forward. It would be of great help if i can get some pointers about how to proceed from here. If possible i want to do this in scipy only and not with opencv.
Rather than simply using the existing scipy functions and algorithms, I also want to learn about the underlying theory so that i can use them efficiently. So please kindly share any helpful theoretical resources.
Thanks in advance
%matplotlib inline
import numpy as np
from scipy import ndimage as nd
import matplotlib.pyplot as plt
from skimage import io
def apply_gradient_threshold(d,thres):
d2 = np.copy(d)
d2[d2 == -thres] = thres
d2[d2 != thres] = 0
return d2
def plot_images(imgs, names):
fig, axes_list = plt.subplots(1, len(imgs), figsize=(20, 20))
for name,axes in zip(names, axes_list):
axes.set_title(name)
for img, axes in zip(imgs, axes_list):
axes.imshow(img, cmap='Greys_r')
plt.show()
img_file = <file_url>
img = plt.imread(img_file)
gray_img = io.imread(img_file, as_gray=True)
if(np.max(gray_img) > 1) :
gray_img = gray_img/255 #normalize
threshold = 0.2
binary = (gray_img > threshold)*1 # convert the grayscale image to binary (monochrome)
im = binary.astype('int32')
dx = nd.sobel(im,1)
dy = nd.sobel(im,0)
dx = apply_gradient_threshold(dx, 4)
dy = apply_gradient_threshold(dy, 4)
mag = np.hypot(dx,dy) #sqrt(dx^2 + dy^2)
mag *= 255.0/np.max(mag)
plot_images([binary, mag ], ['Binary - ' + str(threshold), 'Sobel Filter Result'])
Your image is virtually already made of edges. Use thinning, not an edge filter.

Superimpose heatmap on a base image OpenCV Python

Please look at this github page. I want to generate heat maps in this way using Python PIL,open cv or matplotlib library. Can somebody help me figure it out?
I could create a heat map for my network at the same size as the input, but I am not able superimpose them. The heatmap shape is (800,800) and the base image shape is (800,800,3)
Updated Answer -- 29th April, 2022.
After the repeated comments I have decided to update this post with a better visualization.
Consider the following image:
img = cv2.imread('image_path')
I obtained a binary image after performing binary threshold on the a-channel of the LAB converted image:
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
a_component = lab[:,:,1]
th = cv2.threshold(a_component,140,255,cv2.THRESH_BINARY)[1]
Applying Gaussian blur:
blur = cv2.GaussianBlur(th,(13,13), 11)
The resulting heatmap:
heatmap_img = cv2.applyColorMap(blur, cv2.COLORMAP_JET)
Finally, superimposing the heatmap over the original image:
super_imposed_img = cv2.addWeighted(heatmap_img, 0.5, img, 0.5, 0)
Note: You can vary the weight parameters in the function cv2.addWeighted and observe the differences.
My code starts from a heatmap matrix (224,224) called cam, which is applied to the original image called frame, via opencv;
and it seems to work pretty well:
import numpy as np
from cv2 import cv2
from skimage import exposure
...
capture = cv2.VideoCapture(...)
while True:
ret, frame = capture.read()
if ret:
#resize original frame
frame = cv2.resize(frame, (224, 224))
#get color map
cam = getMap(frame)
map_img = exposure.rescale_intensity(cam, out_range=(0, 255))
map_img = np.uint8(map_img)
heatmap_img = cv2.applyColorMap(map_img, cv2.COLORMAP_JET)
#merge map and frame
fin = cv2.addWeighted(heatmap_img, 0.5, frame, 0.5, 0)
#show result
cv2.imshow('frame', fin)
the getMap() function gets the headmap given the frame;
I found some interesting free videos about this topic:
https://www.youtube.com/watch?v=vTY58-51XZA&t=14s
https://www.youtube.com/watch?v=4v9usdvGU50&t=208s
I had some problems with grayscale images at this line
super_imposed_img = cv2.addWeighted(heatmap_img, 0.5, img, 0.5, 0)
but this one worked for me
plt.imshow(binary_classification_result * 0.99 + original_gray_image * 0.01)

Why HoughCircles returns 0 circles while trying to detect irises?

I am trying to detect the eyes' irises but HoughCircles returns 0 circles.
The input image(eyes) is:
Then I made the following things with this image:
cvtColor(eyes, gray, CV_BGR2GRAY);
morphologyEx(gray, gray, 4,cv::getStructuringElement(cv::MORPH_RECT,cv::Size(3,3)));
threshold(gray, gray, 0, 255, THRESH_OTSU);
vector<Vec3f> circles;
HoughCircles(gray, circles, CV_HOUGH_GRADIENT, 2, gray.rows/4);
if (circles.size())
cout << "found" << endl;
So the final gray image looks like this:
I've found this question Using HoughCircles to detect and measure pupil and iris but it didn't help me despite the similarity with my issue.
So why does HoughCircles return 0 circles while trying to detect irises?
If someone knows any better way to find irises, you are welcome.
I have faced the exact same issue for the same problem. Turns out houghcircles is not a very good method for detecting not-so-well-formed circles.
Feature detection methods like MSER work better in these cases.
import cv2
import math
import numpy as np
import sys
def non_maximal_supression(x):
for f in features:
distx = f.pt[0] - x.pt[0]
disty = f.pt[1] - x.pt[1]
dist = math.sqrt(distx*distx + disty*disty)
if (f.size > x.size) and (dist<f.size/2):
return True
thresh = 70
img = cv2.imread(sys.argv[1])
bw = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
detector = cv2.FeatureDetector_create('MSER')
features = detector.detect(bw)
features.sort(key = lambda x: -x.size)
features = [ x for x in features if x.size > 70]
reduced_features = [x for x in features if not non_maximal_supression(x)]
for rf in reduced_features:
cv2.circle(img, (int(rf.pt[0]), int(rf.pt[1])), int(rf.size/2), (0,0,255), 3)
cv2.imshow("iris detection", img)
cv2.waitKey()
Alternatively you can try convolutional filters.
EDIT:
For the ones who have issues with c++ MSER, here is a basic gist.

Resources