【python-opencv】opencv基础操作之四-人脸裁剪与对齐

1

In [1]:
import cv2
import sys
import numpy as np
import datetime
import os
import glob
from retinaface import RetinaFace
 
/home/shtf2/anaconda3/envs/mxnet/lib/python2.7/site-packages/h5py/__init__.py:36: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 88 from C header, got 96 from PyObject
  from ._conv import register_converters as _register_converters
/home/shtf2/anaconda3/envs/mxnet/lib/python2.7/site-packages/h5py/__init__.py:45: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 88 from C header, got 96 from PyObject
  from . import h5a, h5d, h5ds, h5f, h5fd, h5g, h5r, h5s, h5t, h5p, h5z
/home/shtf2/anaconda3/envs/mxnet/lib/python2.7/site-packages/h5py/_hl/group.py:23: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 88 from C header, got 96 from PyObject
  from .. import h5, h5g, h5i, h5o, h5r, h5t, h5l, h5p, h5s, h5d
In [2]:
thresh = 0.8
scales = [1024, 1980]

count = 1

gpuid = 0
detector = RetinaFace('./model/R50', 0, gpuid, 'net3')
 
[32, 16, 8] {'32': {'ALLOWED_BORDER': 9999, 'BASE_SIZE': 16, 'RATIOS': (1.0,), 'SCALES': (32, 16)}, '8': {'ALLOWED_BORDER': 9999, 'BASE_SIZE': 16, 'RATIOS': (1.0,), 'SCALES': (2, 1)}, '16': {'ALLOWED_BORDER': 9999, 'BASE_SIZE': 16, 'RATIOS': (1.0,), 'SCALES': (8, 4)}}
means [0. 0. 0.]
use_landmarks True
sym size: 9
In [3]:
img = cv2.imread('t1.jpg')
print(img.shape)
im_shape = img.shape
target_size = scales[0]
max_size = scales[1]
im_size_min = np.min(im_shape[0:2])
im_size_max = np.max(im_shape[0:2])
#im_scale = 1.0
#if im_size_min>target_size or im_size_max>max_size:
im_scale = float(target_size) / float(im_size_min)
# prevent bigger axis from being more than max_size:
if np.round(im_scale * im_size_max) > max_size:
    im_scale = float(max_size) / float(im_size_max)

print('im_scale', im_scale)
 
(886, 1280, 3)
('im_scale', 1.1557562076749435)
In [4]:
scales = [im_scale]
flip = False
In [5]:
scales
Out[5]:
[1.1557562076749435]
In [6]:
for c in range(count):
  faces, landmarks = detector.detect(img, thresh, scales=scales, do_flip=flip)
  print(c, faces.shape, landmarks.shape)
 
(0, (6, 5), (6, 5, 2))
In [7]:
c
Out[7]:
0
In [8]:
faces
Out[8]:
array([[2.71104553e+02, 1.49388275e+02, 3.67803711e+02, 2.65329559e+02,
        9.99776781e-01],
       [4.65267273e+02, 2.64880920e+02, 5.72386108e+02, 4.16014465e+02,
        9.99761522e-01],
       [5.41240540e+01, 2.62937775e+02, 1.65135986e+02, 3.96064362e+02,
        9.99760687e-01],
       [9.03860718e+02, 5.40164375e+01, 1.01381720e+03, 2.04063644e+02,
        9.99735057e-01],
       [7.47150696e+02, 3.40924316e+02, 8.44513794e+02, 4.78094055e+02,
        9.99713600e-01],
       [1.13082007e+03, 2.66727417e+02, 1.22397522e+03, 3.98638397e+02,
        9.99278128e-01]])
In [9]:
bbox = faces[0].astype(np.int)
In [10]:
bbox
Out[10]:
array([271, 149, 367, 265,   0])
In [11]:
landmarks
Out[11]:
array([[[ 290.07468 ,  211.11055 ],
        [ 320.754   ,  194.83449 ],
        [ 305.42444 ,  228.3236  ],
        [ 315.17676 ,  247.05186 ],
        [ 337.78192 ,  232.86589 ]],

       [[ 490.03464 ,  321.0317  ],
        [ 542.1663  ,  333.00574 ],
        [ 506.01956 ,  367.30383 ],
        [ 483.95364 ,  370.3372  ],
        [ 532.0355  ,  380.59146 ]],

       [[  86.09296 ,  328.73965 ],
        [ 130.68341 ,  307.31177 ],
        [ 121.310356,  340.69867 ],
        [ 113.14154 ,  370.9015  ],
        [ 148.16147 ,  353.00955 ]],

       [[ 916.7779  ,  120.071045],
        [ 946.9763  ,  116.422424],
        [ 918.8217  ,  151.07452 ],
        [ 937.7643  ,  173.71097 ],
        [ 957.71515 ,  169.39276 ]],

       [[ 761.0399  ,  398.48325 ],
        [ 802.36554 ,  403.34677 ],
        [ 770.85565 ,  430.53915 ],
        [ 764.93164 ,  436.96973 ],
        [ 806.56396 ,  440.20618 ]],

       [[1148.7483  ,  324.59613 ],
        [1192.0652  ,  322.8391  ],
        [1166.7268  ,  349.32642 ],
        [1154.6421  ,  367.24753 ],
        [1192.5304  ,  365.553   ]]], dtype=float32)
In [12]:
landmark5 = landmarks[0].astype(np.int)
In [13]:
landmark5
Out[13]:
array([[290, 211],
       [320, 194],
       [305, 228],
       [315, 247],
       [337, 232]])
In [14]:
cropImg = img[bbox[0]:bbox[2], bbox[1]:bbox[3]]
filename = './cropImg.jpg'
In [15]:
from matplotlib import pyplot as plt

# draw a cvMat using plt.
def draw(image):
        plt.figure(figsize=(15,10)) # 设置画布
        plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
        plt.show()
draw(img)
 
In [16]:
cv2.imwrite(filename, cropImg)
Out[16]:
True
In [17]:
color = (0,0,255)
box = bbox
 

参数解释
第一个参数:img是原图
第二个参数:(x,y)是矩阵的左上点坐标
第三个参数:(x+w,y+h)是矩阵的右下点坐标
第四个参数:(0,255,0)是画线对应的rgb颜色
第五个参数:2是所画的线的宽度

In [18]:
img2 = img.copy() # cpy a new img
cv2.rectangle(img2, (box[0], box[1]), (box[2], box[3]), color, 2)
for l in range(landmark5.shape[0]):
        color = (0,0,255)
        if l==0 or l==3:
          color = (0,255,0)
        cv2.circle(img2, (landmark5[l][0], landmark5[l][1]), 1, color, 2)
draw(img2)
 
In [19]:
draw(img)
 
In [20]:
cropImg = img[bbox[1]:bbox[3], bbox[0]:bbox[2]] # 裁剪坐标为[y0:y1, x0:x1]
draw(cropImg)
 
In [21]:
cropImg.shape
Out[21]:
(116, 96, 3)
In [22]:
# 设置目标长宽
width,height = [112, 112]
dim = (width, height)
In [23]:
# 进行缩放
resized = cv2.resize(cropImg, dim, interpolation=cv2.INTER_AREA)
draw(resized)
 
In [24]:
import cv2
import numpy as np
from skimage import transform as trans

src1 = np.array([
     [51.642,50.115],
     [57.617,49.990],
     [35.740,69.007],
     [51.157,89.050],
     [57.025,89.702]], dtype=np.float32)
#<--left 
src2 = np.array([
    [45.031,50.118],
    [65.568,50.872],
    [39.677,68.111],
    [45.177,86.190],
    [64.246,86.758]], dtype=np.float32)

#---frontal
src3 = np.array([
    [39.730,51.138],
    [72.270,51.138],
    [56.000,68.493],
    [42.463,87.010],
    [69.537,87.010]], dtype=np.float32)

#-->right
src4 = np.array([
    [46.845,50.872],
    [67.382,50.118],
    [72.737,68.111],
    [48.167,86.758],
    [67.236,86.190]], dtype=np.float32)

#-->right profile
src5 = np.array([
    [54.796,49.990],
    [60.771,50.115],
    [76.673,69.007],
    [55.388,89.702],
    [61.257,89.050]], dtype=np.float32)

src = np.array([src1,src2,src3,src4,src5])
src_map = {112 : src, 224 : src*2}

arcface_src = np.array([
  [38.2946, 51.6963],
  [73.5318, 51.5014],
  [56.0252, 71.7366],
  [41.5493, 92.3655],
  [70.7299, 92.2041] ], dtype=np.float32 )

arcface_src = np.expand_dims(arcface_src, axis=0)

# In[66]:

# lmk is prediction; src is template
def estimate_norm(lmk, image_size = 112, mode='arcface'):
  assert lmk.shape==(5,2)
  tform = trans.SimilarityTransform()
  lmk_tran = np.insert(lmk, 2, values=np.ones(5), axis=1)
  min_M = []
  min_index = []
  min_error = float('inf') 
  if mode=='arcface':
    assert image_size==112
    src = arcface_src
  else:
    src = src_map[image_size]
  for i in np.arange(src.shape[0]):
    tform.estimate(lmk, src[i])
    M = tform.params[0:2,:]
    results = np.dot(M, lmk_tran.T)
    results = results.T
    error = np.sum(np.sqrt(np.sum((results - src[i]) ** 2,axis=1)))
#         print(error)
    if error< min_error:
        min_error = error
        min_M = M
        min_index = i
  return min_M, min_index

def norm_crop(img, landmark, image_size=112, mode='arcface'):
  M, pose_index = estimate_norm(landmark, image_size, mode)
  warped = cv2.warpAffine(img, M, (image_size, image_size), borderValue = 0.0)
  return warped
In [25]:
# 人脸校正
warped_img = norm_crop(img, landmark5, image_size=112, mode='arcface') # img 为原大图像, 利用绝对坐标
draw(cropImg)
draw(warped_img)
 
 
In [26]:
import cv2
import requests
import time
from PIL import Image
from io import BytesIO
import numpy as np
from matplotlib import pyplot as plt

%matplotlib inline
# set None proxy设置成没有代理,因为ubuntu终端和浏览器切换代理,老是报错。采取此粗暴的方法。
import os
os.environ['no_proxy'] = '*' 
In [27]:
# get file(of Internet picture)
class InternetPicture:
    def __init__(self, url):
        # attribute
        self.url = url
        self.img = None
        # initial method
        self.get() # self代表类的实例, 而非类本身,所以self.get(self)--> self.get()
        self.show()
        self.info()

    # get Internet Picture
    def get(self):
        for i in range(5): # 多获取几次,增加成功率
            start=time.time()
            file = requests.get(self.url)
            img = cv2.imdecode(np.fromstring(file.content, np.uint8), 1)    #file.content 是读取的远程文件的字节流
            print(i + 1, ' time of Requesting Time:', time.time()-start)
        self.img = img
        print('get a file of:', type(img))
    
    # show image
    def show(self):
        #using plt draw picture
        plt.figure() # 设置画布
        plt.imshow(cv2.cvtColor(self.img, cv2.COLOR_BGR2RGB))
        plt.show()
    
    def info(self):
        # using cv2 to read Internet file of picture
        color_img = self.img
        gray_img = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY)

        # 获取信息:行,列,通道,像素数目,图像数据类型
        print('获取信息:行,列,通道,像素数目,图像数据类型')
        print(color_img.shape, color_img.size, color_img.dtype)
        print(gray_img.shape, gray_img.size, gray_img.dtype)
        print('self.img: get a numpy image')
        print('self.show(): show a numpy image using plt')

        # using PIL.Image to read Internet file of picture
        ## image = Image.open(BytesIO(file.content))
        ## image.show()
        
# draw a cvMat using plt.
def draw(image):
        plt.figure() # 设置画布
        plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
        plt.show()
In [28]:
# 实例化类,并获取一个网络图像
url = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1565251010&di=6420fef2a0e34245435d32e74ff17efd&imgtype=jpg&er=1&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201706%2F11%2F20170611163626_8wmsc.jpeg'
instance = InternetPicture(url)
 
/home/shtf2/anaconda3/envs/mxnet/lib/python2.7/site-packages/ipykernel_launcher.py:17: DeprecationWarning: The binary mode of fromstring is deprecated, as it behaves surprisingly on unicode inputs. Use frombuffer instead
 
(1, ' time of Requesting Time:', 0.07666993141174316)
(2, ' time of Requesting Time:', 0.05942893028259277)
(3, ' time of Requesting Time:', 0.05717897415161133)
(4, ' time of Requesting Time:', 0.059925079345703125)
(5, ' time of Requesting Time:', 0.07864093780517578)
('get a file of:', <type 'numpy.ndarray'>)
 
 
获取信息:行,列,通道,像素数目,图像数据类型
((1146, 1200, 3), 4125600, dtype('uint8'))
((1146, 1200), 1375200, dtype('uint8'))
self.img: get a numpy image
self.show(): show a numpy image using plt
In [29]:
img = instance.img
for c in range(count):
  faces, landmarks = detector.detect(img, thresh, scales=scales, do_flip=flip)
  print(c, faces.shape, landmarks.shape)
 
(0, (1, 5), (1, 5, 2))
In [30]:
# 人脸校正
warped_img = norm_crop(img, landmarks[0], image_size=112, mode='arcface') # img 为原大图像, 利用绝对坐标
bbox = faces[0].astype(np.int)
cropImg = img[bbox[1]:bbox[3], bbox[0]:bbox[2]] # 裁剪坐标为[y0:y1, x0:x1]
draw(cropImg)
draw(warped_img)
 
 
In [ ]:
 

猜你喜欢

转载自www.cnblogs.com/paprikatree/p/11284485.html