import numpy as np
import cv2
im = cv2.imread("goldstandard.png")
nemo = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
hsv_nemo = cv2.cvtColor(nemo, cv2.COLOR_RGB2HSV)
dictionaryHSV = {
"greenCombo": [[30, 126, 87], [70, 255, 250]],
'red': [[0, 92, 212], [10, 265, 255]],
'blue': [[110, 7, 214], [130, 255, 255]],
'black': [[0, 0, 0], [10, 10, 40]],
'another1': [[20, 245, 151], [40, 255, 231]],
'pink': [[140, 126, 215], [160, 146, 255]]
}
for r1, r2 in dictionaryHSV.values():
lower = np.array(r1)
upper = np.array(r2)
mask = cv2.inRange(hsv_nemo, lower, upper)
# cv2.imshow("masked",mask)
# cv2.waitKey(0)
nm = np.ones((nemo.shape[0], nemo.shape[1], nemo.shape[2]), dtype=np.uint8)
for i in range(nm.shape[0]):
for j in range(nm.shape[1]):
nm[i][j] = (255, 255, 255)
result = cv2.bitwise_and(nm, nm, mask=mask)
cv2.imshow("mappped", result)
cv2.waitKey(0)
i have curve plot images and i want to separate all curves based on color i am getting a problem when i come across black curve i get black curve along with black text in the plot i want to only get the curve not the text. I used color ranges in "H.S.V" color-space to recognize colors. Thanks in advance.
Extract region inside square.
Remove all non black pixels.
Find all contours.
Select a biggest contour - it will be your curve.
Related
I am trying to detect the colour of the images using hsv model.
Below is the code that I have used to detect the colour using hsv model.
import os
import numpy as np
import cv2
# map colour names to HSV ranges
color_list = [
['red', [0, 160, 70], [10, 250, 250]],
['pink', [0, 50, 70], [10, 160, 250]],
['yellow', [15, 50, 70], [30, 250, 250]],
['green', [40, 50, 70], [70, 250, 250]],
['cyan', [80, 50, 70], [90, 250, 250]],
['blue', [100, 50, 70], [130, 250, 250]],
['purple', [140, 50, 70], [160, 250, 250]],
['red', [170, 160, 70], [180, 250, 250]],
['pink', [170, 50, 70], [180, 160, 250]]
]
def detect_main_color(hsv_image, colors):
color_found = 'undefined'
max_count = 0
for color_name, lower_val, upper_val in colors:
# threshold the HSV image - any matching color will show up as white
mask = cv2.inRange(hsv_image, np.array(lower_val), np.array(upper_val))
# count white pixels on mask
count = np.sum(mask)
if count > max_count:
color_found = color_name
max_count = count
return color_found
for root, dirs, files in os.walk('C:/Users/User/Desktop/images/'):
f = os.path.basename(root)
for file in files:
img = cv2.imread(os.path.join(root, file))
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
print(f"{file}: {detect_main_color(hsv, color_list)}")
The output
image_1 : blue
image_3 : pink
image_12: purple
...
How can I check the accuracy rate of this trained model?
Any help is appreciated.
Thank you.
By eys I think, or test you code on some pure color images.
I think it is better to clarify the definition of "the colour of the image" firstly. For example, what is the color of this image?
you could compare with colorsys
docs.python.org - colorsys
import colorsys
colorsys.rgb_to_hsv(0.2, 0.4, 0.4) = (0.5, 0.5, 0.4)
colorsys.hsv_to_rgb(0.5, 0.5, 0.4) = (0.2, 0.4, 0.4)
I am using landmark points from dlib library to select the forehead, nose and eye area from my face based on this question: Is there a way to get the area of the forehead (bounding box) by using opencv/dlib and for a live stream video. It works like a charm and i have the points exactly where i want them, what i would like to do is crop the image where the landmarks are set using convexhull polygons.
What i am trying to do is go from this:
to this:
And save it afterwards
Is there a any way to do it? even if it doesn't look pretty. Here's my current code for facial tracking:
import cv2
import dlib
from imutils import face_utils
import imutils
import numpy as np
cap = cv2.VideoCapture(0)
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_81_face_landmarks.dat")
def face_remap(shape):
remapped_image = cv2.convexHull(shape)
return remapped_image
while True:
_, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
out_face = np.zeros_like(frame)
faces = detector(gray, 1)
for face in faces:
x1 = face.left()
y1 = face.top()
x2 = face.right()
y2 = face.bottom()
aam = [17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 77, 75, 75, 55, 69, 70, 71, 80, 72, 73, 79, 74, 78]
landmarks = predictor(gray, face)
shape = face_utils.shape_to_np(landmarks)
remapped_shape = np.zeros_like(shape)
feature_mask = np.zeros((frame.shape[0], frame.shape[1]))
x_pts = []
y_pts = []
for n in (aam):
x = landmarks.part(n).x
y = landmarks.part(n).y
x_pts.append(x)
y_pts.append(y)
cv2.circle(frame, (x, y), 1, (255, 0, 0), -1)
x1 = min(x_pts)
x2 = max(x_pts)
y1 = min(y_pts)
y2 = max(y_pts)
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 3)
cv2.imshow("out", frame)
k = cv2.waitKey(1)
if k == 27:
remapped_shape = face_remap(shape)
cv2.fillConvexPoly(feature_mask, remapped_shape[0:27], 1)
feature_mask = feature_mask.astype(np.bool)
out_face[feature_mask] = frame[feature_mask]
cv2.imwrite("out_face.png", out_face)
break
cap.release()
cv2.destroyAllWindows()
this code will crop the face image from the background and set the landmark as showed in the example. however i would like to crop around the landmarks
You selected only a subset of the 81 landmarks dlib identifies on a face, and discarded the landmarks associated with the mouth, chin and the outer contour of the face.
You should do an additional selection leaving only the points at the boundary of the region you are interested in.
Furthermore, you should order the selected points such that connecting them, in the right order, will form a polygon marking exactly the region you want to crop.
Once you have the polygon you can use this method to crop it:
Use cv2.fillPoly() to draw mask from the polygon.
Get only the cropped polygon portion of the mask from the image using cv2.bitwsie_and().
Get the bounding rect of the cropped region using cv2.boundingRect().
As #Shai mentioned in comments, your shape is not convex at all.
To crop image out of convexhull polygons, you can first get mask out of the convexhull and then apply bitwise and operation on original image using the mask.
Perhaps a function like this would help.
def mask_from_contours(ref_img, contours):
mask = numpy.zeros(ref_img.shape, numpy.uint8)
mask = cv2.drawContours(mask, contours, -1, (255,255,255), -1)
return cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
If you just want crop the image out of the polygon, you can programmatically connect the landmarks, hard-code by landmark index, and get a mask out of the polygon, and then apply bitwise-and operation.
Here's code sample for filling polygon.
import numpy as np
import cv2
import matplotlib.pyplot as plt
a3 = np.array( [[[10,10],[100,10],[100,100],[10,100]]], dtype=np.int32 )
im = np.zeros([240,320],dtype=np.uint8)
cv2.fillPoly( im, a3, 255 )
Let's say I have an image of a book cover that I want to "flatten". To do so it seems like I would need to perform 2 perspective transforms: one just for the front cover and one just for the back cover:
What would be the most efficient way to do this?
Using a 600x600 pixel image homograpy-test.jpg:
import cv2
import numpy as np
#load image
img = cv2.imread('homography-test.jpg', cv2.IMREAD_COLOR)
#corners of book covers (before)
frontCoverPtsBefore = np.array([[32, 48], [279, 136], [247, 430], [39, 281]], dtype="float32")
backCoverPtsBefore = np.array([[279, 136], [474, 36], [463, 316], [247, 430]], dtype="float32")
#corners of book covers (after)
frontCoverPtsAfter = np.array([[0, 0], [299, 0], [299, 599], [0, 599]], dtype="float32")
backCoverPtsAfter = np.array([[300, 0], [599, 0], [599, 599], [300, 599]], dtype="float32")
#get the transformation matrices for both covers
M_front = cv2.getPerspectiveTransform(frontCoverPtsBefore, frontCoverPtsAfter)
M_back = cv2.getPerspectiveTransform(backCoverPtsBefore, backCoverPtsAfter)
#warpPerspective both images
img_front = cv2.warpPerspective(img, M_front, (600, 600))
img_back = cv2.warpPerspective(img, M_back, (600, 600))
#copy half of the warped back cover into the warped front cover
np.copyto(img_front[:, 300:, :], img_back[:, 300:, :])
#display before and after
cv2.imshow('img', img)
cv2.imshow('img_front', img_front)
cv2.waitKey(0)
cv2.destroyAllWindows()
Before and After:
I am using OpenCV's MSER feature detector to find text regions. With the following Python code, I can detect texts (and some non-texts) and draw polygonal curves around each alphabet. Now, I need to plot these texts (more specifically each alphabet) using matplotlib using different colors. Different colors are important here. I am new to matplotlib and I cannot figure out how to implement that. I seek your guidance. I do not need a full solution, but some hints will be helpful.
import numpy as np
import cv2
import matplotlib.pyplot as plt #plt.plot(x,y) plt.show()
img = cv2.imread('TestText.png')
mser = cv2.MSER_create()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
vis = img.copy()
regions = mser.detectRegions(gray, None)
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions]
cv2.polylines(vis, hulls, 1, (0, 255, 0))
# cv2.putText(vis, str('change'), (20, 20), cv2.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 0))
# cv2.fillPoly(vis, hulls, (0, 255, 0))
# cv2.imwrite("test.png", vis)
cv2.imshow('img', vis)
cv2.waitKey(0)
cv2.destroyAllWindows()
May be, you want the result just like Matlab. You should do more steps to do to get the result. Find the coordinates, modify the values with random color.
Here is my Python 3 code for OpenCV 3.3 .
#!/usr/bin/python3
# 2017.10.05 10:52:58 CST
# 2017.10.05 13:27:18 CST
"""
Text detection with MSER, and fill with random colors for each detection.
"""
import numpy as np
import cv2
## Read image and change the color space
imgname = "handicapSign.jpg"
img = cv2.imread(imgname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
## Get mser, and set parameters
mser = cv2.MSER_create()
mser.setMinArea(100)
mser.setMaxArea(800)
## Do mser detection, get the coodinates and bboxes
coordinates, bboxes = mser.detectRegions(gray)
## Filter the coordinates
vis = img.copy()
coords = []
for coord in coordinates:
bbox = cv2.boundingRect(coord)
x,y,w,h = bbox
if w< 10 or h < 10 or w/h > 5 or h/w > 5:
continue
coords.append(coord)
## colors
colors = [[43, 43, 200], [43, 75, 200], [43, 106, 200], [43, 137, 200], [43, 169, 200], [43, 200, 195], [43, 200, 163], [43, 200, 132], [43, 200, 101], [43, 200, 69], [54, 200, 43], [85, 200, 43], [116, 200, 43], [148, 200, 43], [179, 200, 43], [200, 184, 43], [200, 153, 43], [200, 122, 43], [200, 90, 43], [200, 59, 43], [200, 43, 64], [200, 43, 95], [200, 43, 127], [200, 43, 158], [200, 43, 190], [174, 43, 200], [142, 43, 200], [111, 43, 200], [80, 43, 200], [43, 43, 200]]
## Fill with random colors
np.random.seed(0)
canvas1 = img.copy()
canvas2 = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
canvas3 = np.zeros_like(img)
for cnt in coords:
xx = cnt[:,0]
yy = cnt[:,1]
color = colors[np.random.choice(len(colors))]
canvas1[yy, xx] = color
canvas2[yy, xx] = color
canvas3[yy, xx] = color
## Save
cv2.imwrite("result1.png", canvas1)
cv2.imwrite("result2.png", canvas2)
cv2.imwrite("result3.png", canvas3)
The original image (handicapSign.jpg):
The result:
I'm trying to make a mask of all green pixels and one of all yellow pixels using the inrange function. The big trouble I have is finding the correct HSV values for both colors because they seem to overlap.
The following picture (green circle) should detect the green circle only in the yellow mask, this picture (yellow square) must do the opposite (only yellow) but i cannot seem to seperate them.
I use the following HSV values
#Yellow
lower_yellow = np.array([20, 20, 20], dtype=np.uint8)
upper_yellow = np.array([35, 255, 255], dtype=np.uint8)
#Green
lower_green = np.array([24, 40, 40], dtype=np.uint8)
upper_green = np.array([60, 255, 120], dtype=np.uint8)
I hope anyone can help