如何在opencv和python中使眼睛和鼻子变大或变小

Posted

技术标签:

【中文标题】如何在opencv和python中使眼睛和鼻子变大或变小【英文标题】:How make eye and nose bigger or smaller in opencv and python 【发布时间】:2021-12-25 10:52:23 【问题描述】:

我使用以下代码在 OpenCV 和 Python 中选择鼻子我搜索了很多以找到改变鼻子大小并保存为其他图像的方法,但我没有找到任何东西有没有人可以帮助我这样做。

import cv2
import numpy as np
import dlib
img = cv2.imread('1.jpg')
img = cv2.resize(img,(0,0),None,0.5,0.5)
imgOriginal = img.copy()

detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

def createBox(img,points,scale=5):
  bbox = cv2.boundingRect(points)
  x,y,w,h = bbox
  imgCrop = img[y:y+h,x:x+w]
  imgCrop = cv2.resize(imgCrop,(0,0),None,scale,scale)
  return imgCrop


imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
faces = detector(imgGray)
for face in faces:
  x1,y1 = face.left(),face.top()
  x2,y2 = face.right(),face.bottom()
  imgOriginal = cv2.rectangle(img,(x1,y1),(x2,y2),(0,255,0),1)
  landmarks = predictor(imgGray,face)
  myPoints=[]
  for n in range(68):
    x = landmarks.part(n).x
    y = landmarks.part(n).y
    myPoints.append([x,y])
    #cv2.circle(imgOriginal,(x,y),5,(50,50,255),cv2.FILLED)
    #cv2.putText(imgOriginal,str(n),(x,y-10),cv2.FONT_HERSHEY_COMPLEX_SMALL,0.8,(0,0,255),1)
  myPoints = np.array(myPoints)
  #nose points to select
  #nose_points = myPoints[27:35]

print(myPoints)
cv2_imshow(imgOriginal)
cv2.waitKey(0)


提前致谢

【问题讨论】:

【参考方案1】:

我认为您需要“膨胀”效果,例如内爆和爆炸。在 OpenCV 中没有这些过滤器的实现,但是您可以找到其他工具,例如 Wand(ImageMagick 的 Python 绑定),它们具有 implode/explode。

示例(魔杖):

from wand.image import Image

with Image(filename="test.jpg") as img:
    img.implode(amount = -0.2)
    img.save(filename="destination.jpg")
    # img_array = numpy.asarray(img) --> you can convert wand.image.Image to numpy array for further uses

将负值传递给 implode 函数等同于进行爆炸。所以为了放大效果使用负值。

但有一个问题:img.implode 在图像的中心执行,因此在找到面部特征(眼睛、鼻子……)后,您需要以某种方式移动图片以制作眼睛或鼻子位于图像的中心。之后,您可以简单地使用 implode 函数。

【讨论】:

【参考方案2】:

这是在 Python/OpenCV 的局部区域中使用球形(气泡)扭曲的一种方法。

 - Define region center and radius and amount of spherical distortion
 - Crop the image for that center and radius
 - Compute the spherical distortion x and y displacement maps and a binary mask
 - Apply the distortion maps using cv2.remap
 - Antialias the mask
 - Merge the distorted and cropped image using the mask
 - Insert that merged image into the original image
 - Save the results

输入:

import numpy as np
import cv2
import math
import skimage.exposure

img = cv2.imread("portrait_of_mussorgsky2.jpg")

# set location and radius
cx = 130
cy = 109
radius = 30

# set distortion gain
gain = 1.5

# crop image 
crop = img[cy-radius:cy+radius, cx-radius:cx+radius]

# get dimensions
ht, wd = crop.shape[:2]
xcent = wd / 2
ycent = ht / 2
rad = min(xcent,ycent)

# set up the x and y maps as float32
map_x = np.zeros((ht, wd), np.float32)
map_y = np.zeros((ht, wd), np.float32)
mask = np.zeros((ht, wd), np.uint8)

# create map with the spherize distortion formula --- arcsin(r)
# xcomp = arcsin(r)*x/r; ycomp = arsin(r)*y/r
for y in range(ht):
    Y = (y - ycent)/ycent
    for x in range(wd):
        X = (x - xcent)/xcent
        R = math.hypot(X,Y)
        if R == 0:
            map_x[y, x] = x
            map_y[y, x] = y
            mask[y,x] = 255
        elif R >= .90:    # avoid extreme blurring near R = 1
            map_x[y, x] = x
            map_y[y, x] = y
            mask[y,x] = 0
        elif gain >= 0:
            map_x[y, x] = xcent*X*math.pow((2/math.pi)*(math.asin(R)/R), gain) + xcent
            map_y[y, x] = ycent*Y*math.pow((2/math.pi)*(math.asin(R)/R), gain) + ycent
            mask[y,x] = 255
        elif gain < 0:
            gain2 = -gain
            map_x[y, x] = xcent*X*math.pow((math.sin(math.pi*R/2)/R), gain2) + xcent
            map_y[y, x] = ycent*Y*math.pow((math.sin(math.pi*R/2)/R), gain2) + ycent
            mask[y,x] = 255

# remap using map_x and map_y
bump = cv2.remap(crop, map_x, map_y, cv2.INTER_LINEAR, borderMode = cv2.BORDER_CONSTANT, borderValue=(0,0,0))

# antialias edge of mask
# (pad so blur does not extend to edges of image, then crop later)
blur = 7
mask = cv2.copyMakeBorder(mask, blur,blur,blur,blur, borderType=cv2.BORDER_CONSTANT, value=(0))
mask = cv2.GaussianBlur(mask, (0,0), sigmaX=blur, sigmaY=blur, borderType = cv2.BORDER_DEFAULT)
h, w = mask.shape
mask = mask[blur:h-blur, blur:w-blur]
mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
mask = skimage.exposure.rescale_intensity(mask, in_range=(127.5,255), out_range=(0,1))

# merge bump with crop using grayscale (not binary) mask
bumped = (bump * mask + crop * (1-mask)).clip(0,255).astype(np.uint8)

# insert bumped image into original
result = img.copy()
result[cy-radius:cy+radius, cx-radius:cx+radius] = bumped

# save results
cv2.imwrite("portrait_of_mussorgsky2_bump.jpg", result)

# display images
cv2.imshow('img', img)
cv2.imshow('crop', crop)
cv2.imshow('bump', bump)
cv2.imshow('mask', mask)
cv2.imshow('bumped', bumped)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果图像:

【讨论】:

以上是关于如何在opencv和python中使眼睛和鼻子变大或变小的主要内容,如果未能解决你的问题,请参考以下文章

使用opencv在鼻子和眼睛轴上旋转图像

OpenCV3计算机视觉+Python

Need Haar Cascades 用于鼻子、眼睛和嘴唇(嘴)

AI教程:Q版卡通人物头像插画

使用matlab机器视觉工具箱实现人脸特征的检测和定位,识别并标注眉毛,眼睛,鼻子,嘴巴

使用 OpenCV Android 进行面部特征检测