Introduction I wanted something like this ↓ ↓ ↓
The figure is too cheap.
When verbalized, ** Detect objects of a specific color and size from images that display objects of various colors and sizes ** I wanted to do that.
I think there are many excellent commentary articles already, but if I don't write these, I'll forget them soon, so I'll write them as a memorandum.
The image is processed in the following 4 steps
Binarization based on color information
Detect contour
Case classification by size
Overlay the outline on the original image
** 1. Binarization based on color information ** ** 2. Detect contour **
import cv2
import numpy as np
#image"hoge.jpg "Read
#The same image is read twice with different variables. One (img_c) for "image processing",
#The other (img_c_Since origin) is "for displaying on top of the outline".
filename = "hoge.jpg "
input_img = filename
img_c = cv2.imread(input_img)
img_c_origin = cv2.imread(input_img)
#Pretreatment (blurring)
#Numbers are appropriate
for i in range(2):
img_c = cv2.GaussianBlur(img_c,(5,5),0)
#Separate image channels. cv2.Note that the images read by imread are in the order of "BGR" instead of "RGB"!
B, G, R = cv2.split(img_c)
#Binarize each RGB channel.
#It will be 1 if the pixel is the desired color and 0 otherwise.
# -------- color condition ----------
R_low = 0
R_high = 100
G_low = 100
G_high = 200
B_low = 200
B_high = 250
# -----------------------------------
img_r_th = np.where((R < R_high) & (R > R_low), 1, 0)
img_g_th = np.where((G < G_high) & (G > G_low), 1, 0)
img_b_th = np.where((B < B_high) & (B > B_low), 1, 0)
#Multiplication of each element, not matrix multiplication. I like it because I can do this.
#Logical AND(AND)It is an image to take. In order to make the detected object white, it is multiplied by 255 at the end.
img_th = img_r_th * img_g_th * img_b_th * 255
#Cast to uint8 for use as an argument to the next findCOntours.
img_th = np.uint8(img_th)
#Detects contours.
contours = cv2.findContours(img_th, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]
For the reason why image blurring (preprocessing) is necessary, the "preprocessing" in the following article was helpful. Introduction to OpenCV for Machine Learning
This time, I'm using RGB for various reasons, but there is also a way to detect it with HSV. It's intuitive, isn't it? Object contour detection
Click here for details on contour detection Outline: First Step
Although I have written various things, the area around contour detection is almost sutra copying. Because it's stupid ...
** 3. Case by size ** ** 4. Display overlaid with the original image **
# -------- scale condition ----------
Area_th_min = 1
Area_th_max = 1000
# -----------------------------------
#Define a list to store the contours you want
Active_contours = []
#When you type a contour into the contourArea, the area of the area surrounded by the contour is returned.
#By using this, only the object (outline) of a specific size is Active._Store in contours.
for cont in contours:
if cv2.contourArea(cont) > Area_th_min and cv2.contourArea(cont) < Area_th_max:
Active_contours.append(cont)
#You can use drowContours to overlay an outline on an image.
#For details, see "Outline: First Step" above.
cont_img = cv2.drawContours(img_c_origin, Active_contours, -1, (255,0,0), 3)
#Convert "BGR" to "RGB" for display.
cont_img = cv2.cvtColor(cont_img, cv2.COLOR_BGR2RGB)
** Whole code **
detect_color.py
import cv2
import numpy as np
import matplotlib.pyplot as plt
#[[User specified parameters]]
# ------- color condition ----------
R_low = 200
R_high = 250
G_low = 60
G_high = 110
B_low = 80
B_high = 120
# -----------------------------------
# ------- scale condition -----------
Area_th_min = 1200
Area_th_max = 10000
# -----------------------------------
# Step 1 ---------------------------
filename = "hoge.jpg "
input_img = filename
img_c = cv2.imread(input_img)
img_c_origin = cv2.imread(input_img)
for i in range(2):
img_c = cv2.GaussianBlur(img_c,(5,5),0)
B, G, R = cv2.split(img_c)
img_g_th = np.where((G < G_high) & (G > G_low), 1, 0)
img_b_th = np.where((B < B_high) & (B > B_low), 1, 0)
img_r_th = np.where((R < R_high) & (R > R_low), 1, 0)
img_th = img_r_th * img_g_th * img_b_th * 255
img_th = np.uint8(img_th)
# Step 2 ---------------------------
contours = cv2.findContours(img_th, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]
# Step 3 ---------------------------
Active_contours = []
for cont in contours:
if cv2.contourArea(cont) > Area_th_min and cv2.contourArea(cont) < Area_th_max:
Active_contours.append(cont)
# Step 4 ---------------------------
cont_img = cv2.drawContours(img_c_origin, Active_contours, -1, (255,0,0), 3)
cont_img = cv2.cvtColor(cont_img, cv2.COLOR_BGR2RGB)
img_c_origin = cv2.cvtColor(img_c_origin, cv2.COLOR_BGR2RGB)
# ------------- show images -------------
plt.gray()
plt.subplot(1,2,1)
plt.imshow(img_th, vmin=0, vmax=255, interpolation = 'none')
plt.title('Threshold')
plt.subplot(1,2,2)
plt.imshow(cont_img, interpolation = 'none')
plt.title('Contour')
plt.show()
# ----------------------------------------
The above code already specifies a range of R, G, B. Here, if you specify the insanely cool logo of "The Demon Girl Next Door", which is the English title of "The Demon Girl Next Door", as the input image ...
Only the pink "G" is detected. In the Threshold image, all pink areas were detected, but as a result of classifying by size, only G remained.
By the way, I think this logo image, black represents Shamiko, and pink represents peach, but what about ... The Demon Girl Next Door can be seen on Amazon, so let's all see it.
The end
Recommended Posts