最近又看了一遍忍界大战,试着做一个自动添加写轮眼的玩意儿。
思路:人脸检测——人眼检测——瞳孔分割——写轮眼添加——融合
opencv用的cascade进行人眼和人脸识别
import numpy as np
import cv2
import os
# multiple cascades: https://github.com/Itseez/opencv/tree/master/data/haarcascades
face_cascade = cv2.CascadeClassifier('.\\data\\haarcascades\\haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('.\\data\\haarcascades\\haarcascade_eye_tree_eyeglasses.xml')
index = 0
for root,dir_,files in os.walk("face_data"):
for file_ in files:
print(os.path.join(root,file_))
img = cv2.imread(os.path.join(root,file_))
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
#人脸区域框
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
#在检测到的人脸区域内检测眼睛
eyes = eye_cascade.detectMultiScale(roi_gray)
for (ex,ey,ew,eh) in eyes:
if ew*eh<(w*h)//50:
continue
#眼睛区域框
eye_color = roi_color.copy()
cv2.rectangle(roi_color,(ex-10,ey-10),(ex+ew+10,ey+eh+10),(0,255,0),2)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'Eye',(ex+x,ey+y), font, 0.5, (11,255,255), 1, cv2.LINE_AA)
# cv2.imshow('eye', eye_color[ey-10:ey+eh+10,ex-10:ex+ew+10])
# cv2.waitKey()
cv2.imwrite("eye_data/"+str(index)+".jpg",eye_color[ey-10:ey+eh+10,ex-10:ex+ew+10])
index = index+1
cv2.namedWindow('img', 1)
cv2.imshow('img',img)
cv2.waitKey()
瞳孔分割用了U^2net进行了训练,数据标了几十个
https://github.com/NathanUA/U-2-Net
最后就是写轮眼添加,写轮眼加到瞳孔分割的部分
import cv2
import numpy as np
import os
def drawInCircle(img_open, img, cont, cX, cY):
# 绘制最大内接圆 # 最大内接圆——检索轮廓的方式
c = cont # 单个轮廓
contours = cv2.findContours(img_open.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
src = img_open.copy()
raw_dist = np.empty(src.shape, dtype=np.float32)
for ii in range(src.shape[0]):
for jj in range(src.shape[1]):
raw_dist[ii, jj] = cv2.pointPolygonTest(c, (jj, ii), True) # 检测点坐标,与c轮廓坐标的距离
minVal, maxVal, _, maxDistPt = cv2.minMaxLoc(raw_dist) # minMaxLoc查找最小和最大元素值及其位置ma
maxVal = abs(maxVal)
cv2.circle(img, (cX, cY), np.int(maxVal)-1, (255, 255, 255), 1, cv2.LINE_8, 0) # 最大内接圆
height = np.int(maxVal)-1
return np.int(maxVal)-1
#def set_eye():\
xly = cv2.imread("xly.png",cv2.IMREAD_UNCHANGED)
b_channel, g_channel, r_channel, alph = cv2.split(xly)
for root,dir_,files in os.walk('eye_data'):
for index,file_ in enumerate(files):
file_mask = os.path.join("eye_mask",file_)
pic_mask = cv2.imread(file_mask)
pic_eye = cv2.imread(os.path.join(root,file_))
gray = cv2.cvtColor(pic_mask,cv2.COLOR_BGR2GRAY)
_,th_img = cv2.threshold(gray,100,255,cv2.THRESH_BINARY)
contours, hier = cv2.findContours(th_img,
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
center,radius = cv2.minEnclosingCircle(contours[0])
r = int(radius)
cX,cY = (int(center[0]),int(center[1]))
pic_mask = cv2.circle(pic_mask,(cX,cY),r,(255,255,0),2)
xly = cv2.resize(xly,(2*r,2*r))
xly_roi = pic_eye[cY-r:cY+r,cX-r:cX+r]
th_img_roi = th_img[cY-r:cY+r,cX-r:cX+r]
for x in range(xly_roi.shape[0]): # 图片的高
for y in range(xly_roi.shape[1]): # 图片的宽
px = xly[x,y]
if px[3]>0 and th_img_roi[x,y]>0:
px1 = px[:-1]
tx = 0.5*xly_roi[x,y]+0.5*px1
xly_roi[x,y] = tx
cv2.imshow('pic_mask',pic_eye)
cv2.waitKey()
最终效果:
搞定!