人脸识别与美颜算法实战-图像特效

哈哈镜

输入图像f(x,y),宽高分别为Width和Height,设置图像中心坐标 Center(cx,xy)为缩放中心点,图像上任意一点到中心点的相对坐标 tx=x-cx,ty=y-cy。哈哈镜效果分为图像拉伸放大和图像缩小。

对于图像拉伸放大,设置图像变换的半径为radius,哈哈镜变换 后的图像为p(x,y)。

x=(tx/2)×(sqrt(tx×tx+ty×ty)/radius)+cx

y=(ty/2)×(sqrt(tx×tx+ty×ty)/radius)+cy

对于图像缩小,设置图像变换的半径为radius,哈哈镜变换后的 图像为p(x,y)。

x=cos(atan2(ty,tx))×12×(sqrt(tx×tx+ty×ty)+cx

y=sin(atan2(ty,tx))×12×(sqrt(tx×tx+ty×ty)+cy

# -*- coding: UTF-8 -*-
import cv2
import numpy as np
import math

def MaxFrame(frame):
    height, width, n = frame.shape
    center_X = width / 2
    center_Y = height / 2
    radius = 200
    real_radius =int(radius / 2.0)
    new_data = frame.copy()

    for i in range(width):
        for j in range(height):
            tX = i - center_X
            tY = j - center_Y

            distance = tX * tX + tY * tY
            if distance < radius * radius:

                newX = int(tX/ 2.0)
                newY = int(tY/ 2.0)

                newX = int(newX * (math.sqrt(distance) / real_radius))
                newX = int(newX * (math.sqrt(distance)/ real_radius))

                newX = int(newX + center_X)
                newY = int(newY + center_Y)
                if newX<width and newY<height:
                    new_data[j, i] = frame[newY, newX]
                    new_data[j, i] = frame[newY, newX]
                    new_data[j, i] = frame[newY, newX]

            else:
                new_data[j, i] = frame[j, i]
                new_data[j, i] = frame[j, i]
                new_data[j, i] = frame[j, i]

    return new_data

def MinFrame(frame):
    height, width, n = frame.shape
    center_X = width / 2
    center_Y = height / 2
    new_data = frame.copy()

    for i in range(width):
        for j in range(height):
            tX = i - center_X
            tY = j - center_Y
            theta = math.atan2(tY, tX)
            radius = math.sqrt((tX * tX) + (tY * tY))

            newR = math.sqrt(radius) *12
            newX = int(center_X + (newR * math.cos(theta)))
            newY = int(center_Y + (newR * math.sin(theta)))

            if newX < 0 and  newX >width:
                newX = 0

            if newY <0 and newY >height:
                newY = 0

            if newX<width and newY<height:
                new_data[j, i][0] = frame[newY, newX][0]
                new_data[j, i][1] = frame[newY, newX][1]
                new_data[j, i][2] = frame[newY, newX][2]

            else:
                new_data[j, i][0] = frame[j, i][0]
                new_data[j, i][1] = frame[j, i][1]
                new_data[j, i][2] = frame[j, i][2]

    return new_data

def main():
    img = cv2.imread("8.jpg")

    cv2.imshow("original", img)
    img2=MaxFrame(img)
    cv2.imshow("enlarge", img2)
    img3 = MinFrame(img)
    cv2.imshow("ensmall", img3)
    cv2.waitKey(0)

if __name__ == '__main__':
    main()

 这种图像变 形的原理很简单,就是求解变换后坐标和变换前坐标的坐标方程。接 下来可以按照上面的例子直接赋值,也可以采取插值的方法得到输出 图像。

怀旧风格

怀旧风格的设计主要是在图像的颜色空间进行处理,以GRB空间为 例,对R、G、B这3个通道的颜色数值进行处理,让图像有一种泛黄的 老照片效果。设计的转换公式如下:

import cv2
import numpy as np

def retro_style(img):
    b,g,r=cv2.split(img)
    B=(0.272*r + 0.534*g + 0.131*b)
    G=(0.349*r + 0.686*g + 0.168*b)
    R = (0.393 * r + 0.769 * g + 0.189 * b)
    img2=cv2.merge([B,G,R])
    img2=np.clip(img2,0,255)
    img2=img2.astype(np.uint8)
    return img2

def main():
    img = cv2.imread('8.jpg')
    img2=retro_style(img)
    cv2.imshow("img", np.hstack([img,img2]))
    cv2.waitKey(0)

if __name__ == '__main__':
    main()

马赛克算法原理

马赛克效果其实就是将图像分成大小一致的图像块,每一个图像 块都是一个正方形,并且在这个正方形中所有像素值都相等。

其实现的思路是,将这个马赛克中一个个小正方形看成模板窗 口。马赛克的编码方式有很多种,常见的如下:

  1. ·模板中对应的所有图像的像素值都等于该模板的左上角第一个 像素的像素值。
  2. ·对于方块里的像素进行随机打乱。
  3. ·随机用某一点代替领域类的所有像素。
from skimage import img_as_float
import matplotlib.pyplot as plt
from skimage import io
import random
import numpy as np
file_name='4.jpg'
img=io.imread(file_name)
img = img_as_float(img)
img_out = img.copy()
row, col, channel = img.shape
half_patch =40
for i in range(half_patch, row-1-half_patch, half_patch):
  for j in range (half_patch, col-1-half_patch, half_patch):
    k1 = random.random() - 0.5
    k2 = random.random() - 0.5
    m=np.floor(k1*(half_patch*2 + 1))
    n=np.floor(k2*(half_patch*2 + 1))
    h=int((i+m) % row)
    w=int((j+n) % col)
    img_out[i-half_patch:i+half_patch, j-half_patch:j+half_patch, :] =\
            img[h, w, :]
# plt.figure(1)
# plt.imshow(img)
# plt.axis('off')
plt.figure(2)
plt.imshow(img_out)
plt.axis('off')
plt.show()

漫画风格算法原理

算法的设计思路如下:

(1)将彩色图像转换成灰度图像。

(2)边缘检测提取灰度图像的边缘。

(3)对于检测的边缘进行增强并二值化产生粗线条的特征图像。

(4)将处理完的图像与原图进行叠加,得到最终效果

边缘提取和二值化可以采用OpenCV自带的自适应阈值二值化函数
adaptiveThreshold()来解决。函数声明如下:
dst = cv2.adaptiveThreshold(src, maxval, thresh_type, type, Block Size,
C)
参数说明:
·src:输入图,只能输入单通道图像,通常来说为灰度图。
·dst:输出图。
·maxval:当像素值超过了阈值(或者小于阈值,根据type来决定
所赋予的值。)
·thresh_type:阈值的计算方法包含两种类型,即
cv2.ADAPTIVE_THRESH_MEAN_C和
cv2.ADAPTIVE_THRESH_GAUSSIAN_C。
·type:二值化操作的类型与固定阈值函数相同,包含5种类型,
即cv2.THRESH_BINARY、cv2.THRESH_BINARY_INV、
cv2.THRESH_TRUNC、cv2.THRESH_TOZERO和
cv2.THRESH_TOZERO_INV。
·Block Size:图片中分块的大小。
·C:阈值计算方法中的常数项。

图像阈值化的目的是从灰度图像中分离目标区域和背景区域。因 为在灰度图像中,灰度值变化明显的区域往往是物体的轮廓,所以将 图像分成一小块一小块地去计算阈值会得出图像的轮廓。

import cv2

def main():

 img_rgb = cv2.imread("4.jpg")  #读取图片
 img_color = img_rgb
 img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)
 img_blur = cv2.medianBlur(img_gray, 7)
 #检测到边缘并且增强其效果
 img_edge = cv2.adaptiveThreshold(img_blur,255,
          cv2.ADAPTIVE_THRESH_MEAN_C,
          cv2.THRESH_BINARY,
          blockSize=9,
          C=2)
 #转换回彩色图像
 img_edge = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2RGB)
 img_cartoon = cv2.bitwise_and(img_color, img_edge)
 # 保存转换后的图片
 cv2.imshow("out", img_cartoon)
 cv2.waitKey(0)


if __name__ == '__main__':
     main()

猜你喜欢

转载自blog.csdn.net/qq_40107571/article/details/128483489