opencv-python 小白笔记(21)

好多天没有写博客了,这几天一直忙于炼丹,快被数据搞疯了。废话不多说,今天主要写美颜相关

(一)亮度增强

其实直方图均衡化也可以增加图像亮度,下面先用直方图均衡化的方式实现亮度的增强(以前已经写过灰度图的直方图均衡化,这里相当于彩图的均衡化)


import cv2

img= cv2.imread('face.jpg')

cv2.imshow('img', img)#这里展示一下原图

b,g,r=cv2.split(img)

b = cv2.equalizeHist(b)
g = cv2.equalizeHist(g)
r = cv2.equalizeHist(r)

out_put=cv2.merge((b,g,r))

cv2.imshow('out_put',out_put)
cv2.waitKey(0)

这里相当于分别对三通道进行图像均衡化
在这里插入图片描述
雀斑已经淡了很多了,也变白了。(个人觉的,opencv为啥不直接出以个彩图均衡化的函数)

这里使用另一种方法增加图像的亮度,而这种写法有两种
法一:

import cv2
import numpy as np


def empty(a):
    pass


cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars",650,47)
cv2.createTrackbar("light","TrackBars",0,100,empty)#这里设置light最大值为100,你也可以设置大一点

while True:
    img= cv2.imread('face.jpg')

    h,w=img.shape[:2]
    #print(h,w)

    cv2.imshow('img', img)#这里展示一下原图

    light = cv2.getTrackbarPos("light", "TrackBars")

    out_put=np.zeros((h,w,3),np.uint8)

    for i in range(0,h):
        for j in range(0,w):
            b,g,r=img[i,j]

            x=int(b)+light
            y=int(g)+light
            z=int(r)+light

            if x>255:
                x=255
            if y>255:
                y=255
            if z>255:
                z=255

            out_put[i, j] = x, y, z

    cv2.imshow('out_put',out_put)
    cv2.waitKey(1)

法二:

import cv2

def empty(a):
    pass

cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars",650,47)
cv2.createTrackbar("light","TrackBars",0,100,empty)#这里设置light最大值为100

while True:
    img= cv2.imread('face.jpg')


    cv2.imshow('img', img)#这里展示一下原图

    light = cv2.getTrackbarPos("light", "TrackBars")

    b,g,r=cv2.split(img)

    b=b+light#这里注意相加的值不要超过255
    g=g+light#这里注意相加的值不要超过255
    r=r+light#这里注意相加的值不要超过255

    out_put=cv2.merge((b,g,r))

    cv2.imshow('out_put',out_put)
    cv2.waitKey(1)

在这里插入图片描述
这里明显右边的要白一点,雀斑也淡了一些

(二)磨皮美白(cv2.bilateralFilter)

这主要用到cv2.bilateralFilter双边滤波函数

参数解释
src输入图像
d过滤时周围每个像素领域的直径
sigmaColor在color space中过滤sigma。参数越大,临近像素将会在越远的地方mix。
sigmaSpace在coordinate space中过滤sigma。参数越大,那些颜色足够相近的的颜色的影响越大。

看看代码吧:

import cv2


def empty(a):
    pass


cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars",650,150)
cv2.createTrackbar("d","TrackBars",0,255,empty)
cv2.createTrackbar("sigmaColor","TrackBars",0,255,empty)
cv2.createTrackbar("sigmaSpace","TrackBars",0,255,empty)

while True:
    img= cv2.imread('face2.jpg')

    cv2.imshow('img', img)#这里展示一下原图

    d=cv2.getTrackbarPos("d","TrackBars")
    sigmaColor=cv2.getTrackbarPos("sigmaColor", "TrackBars")
    sigmaSpace=cv2.getTrackbarPos("sigmaSpace", "TrackBars")

    output = cv2.bilateralFilter(img, d, sigmaColor, sigmaSpace)#然而我不知道为什么,觉得这些雀斑挺可爱的

    #output=cv2.bilateralFilter(img,15,35,35)#这里感觉这几个值效果较好,当然并不绝对
    cv2.imshow('output',output)
    cv2.waitKey(1)

在这里插入图片描述
这效果还是不错的,但不知为什么,我觉得这雀斑挺可爱的,好吧这时可能会有人说直男

(三)瘦脸(局部平移算法)

在这里插入图片描述

这里需要用到到前一节中人脸关键点定位(68点),瘦左脸,计算3号点到5号点的距离作为瘦脸最大参考距离,瘦右脸,计算13号点到15号点的距离作为瘦脸的最大参考距离。这里实现的是简易瘦脸,不同的图像的效果不一样,下面有Trackbar调节瘦脸的程度

#导入工具包
from scipy.spatial import distance
import numpy as np
import dlib
import cv2
import math



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

def bilinear_insert(image, new_x, new_y):
    """
    双线性插值法
    """
    w, h, c = image.shape
    if c == 3:
        x1 = int(new_x)
        x2 = x1 + 1
        y1 = int(new_y)
        y2 = y1 + 1

        part1 = image[y1, x1].astype(np.float) * (float(x2) - new_x) * (float(y2) - new_y)
        part2 = image[y1, x2].astype(np.float) * (new_x - float(x1)) * (float(y2) - new_y)
        part3 = image[y2, x1].astype(np.float) * (float(x2) - new_x) * (new_y - float(y1))
        part4 = image[y2, x2].astype(np.float) * (new_x - float(x1)) * (new_y - float(y1))

        insertValue = part1 + part2 + part3 + part4

        return insertValue.astype(np.int8)


def local_traslation_warp(image, start_point, end_point, radius):
	"""
    局部平移算法
    """
	radius_square = math.pow(radius, 2)
	image_cp = image.copy()

	dist_se = math.pow(np.linalg.norm(end_point - start_point), 2)
	height, width, channel = image.shape
	for i in range(width):
		for j in range(height):
			# 计算该点是否在形变圆的范围之内
			# 优化,第一步,直接判断是会在(start_point[0], start_point[1])的矩阵框中
			if math.fabs(i - start_point[0]) > radius and math.fabs(j - start_point[1]) > radius:
				continue

			distance = (i - start_point[0]) * (i - start_point[0]) + (j - start_point[1]) * (j - start_point[1])

			if (distance < radius_square):
				# 计算出(i,j)坐标的原坐标
				# 计算公式中右边平方号里的部分
				ratio = (radius_square - distance) / (radius_square - distance + dist_se)
				ratio = ratio * ratio

				# 映射原位置
				new_x = i - ratio * (end_point[0] - start_point[0])
				new_y = j - ratio * (end_point[1] - start_point[1])

				new_x = new_x if new_x >= 0 else 0
				new_x = new_x if new_x < height - 1 else height - 2
				new_y = new_y if new_y >= 0 else 0
				new_y = new_y if new_y < width - 1 else width - 2

				# 根据双线性插值法得到new_x, new_y的值
				image_cp[j, i] = bilinear_insert(image, new_x, new_y)

	return image_cp

def empty(a):
    pass

cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars", 650, 70)
cv2.createTrackbar("dist_left", "TrackBars", 0, 100, empty)  # 这里设置dist_left最大值为100
cv2.createTrackbar("dist_right", "TrackBars", 0, 100, empty)  # 这里设置dist_right最大值为100

while True:

	img=cv2.imread('1.jpg')
	img1=img.copy()


	gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

	# 检测人脸
	rects = detector(gray, 0)

	# 遍历每一个检测到的人脸
	for rect in rects:
		# 获取坐标
		result = predictor(gray, rect)
		result=result.parts()
		points = [[p.x, p.y] for p in result]
		#print(type(points))#类型为list


		points=np.array(points)#这里需将上面的points转化为数组
		#print(points)

		for (x, y) in points[:]:
			# print(rects.parts())
			cv2.circle(img1, (x, y), 3, (0, 255, 0), -1)  # 还是原谅色

	#这一块主要用来瘦脸
	############################################################################################

		#out_put = thin_face(img, points)

		end_point = points[29]  # 30号点

		# 瘦左脸,计算3号点到5号点的距离作为瘦脸最大参考距离
		dist_left = distance.euclidean(points[3], points[5])
		print(dist_left)

		dist_left = cv2.getTrackbarPos("dist_left", "TrackBars")
		out_put = local_traslation_warp(img, points[3], end_point, dist_left)

		# 瘦右脸,计算13号点到15号点的距离作为瘦脸的最大参考距离
		dist_right = distance.euclidean(points[13], points[15])
		print(dist_right)

		dist_right = cv2.getTrackbarPos("dist_right", "TrackBars")
		out_put = local_traslation_warp(out_put, points[14], end_point, dist_right)

	############################################################################################
		cv2.imshow("img", img)
		cv2.imshow('img1',img1)
		cv2.imshow("out_put",out_put)
		cv2.waitKey(1)


在这里插入图片描述
上面分别是原图、人脸关键点的定位图、瘦脸结果图。虽然结果不明显,但是还是可以勉强可以看出下面的结果图的脸颊两侧要略瘦

(四)红唇

这个就比较简单了,找到嘴唇部分的关键点,然后凸包填充就可以了,当然只要你愿意,你可以对下面代码中red_lip()函数进行修改,对颜色及深度做更为细致的修改

import numpy as np
import dlib
import cv2

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


def red_lip(img, points, color):  # 其实在里并不严谨,因为在里将牙齿也变红了,其所也不难,只要在扣嘴唇轮廓时将牙齿i轮廓给扣调就可以了
	hull = cv2.convexHull(points)  # 先计算嘴唇凸包(即获取嘴唇轮廓)

	#  为了不影响图片效果,因为后面是将两张图片加权叠加,所以下面先生成和原图大小相同的图片,并在上面绘制嘴唇轮廓
	mask = np.zeros_like(gray)
	cv2.fillPoly(mask, np.array([hull]), 255)
	roi = cv2.bitwise_and(gray, gray, mask=mask)
	roi = np.stack((roi,) * 3, axis=-1)

	roi = cv2.drawContours(roi, [hull], -1, (0, 0, color), -1)
	cv2.imshow("roi", roi)

	image = cv2.addWeighted(roi, 0.2, img.copy(), 0.9, 0)
	return image


def empty(a):
	pass


cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars", 650, 70)
cv2.createTrackbar("color", "TrackBars", 0, 255, empty)  # 这里设置color最大值为255

while True:

	img = cv2.imread('input/1.png')
	img1 = img.copy()
	img2 = img.copy()

	gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

	# 检测人脸
	rects = detector(gray, 0)

	# 遍历每一个检测到的人脸
	for rect in rects:
		# 获取坐标
		result = predictor(gray, rect)
		result = result.parts()
		points = [[p.x, p.y] for p in result]
		# print(type(points))#类型为list

		points = np.array(points)  # 这里需将上面的points转化为数组
		# print(points)

		for (x, y) in points[:]:
			# print(rects.parts())
			cv2.circle(img1, (x, y), 3, (0, 255, 0), -1)  # 还是原谅色

		# 嘴唇变红
		color = cv2.getTrackbarPos("color", "TrackBars")
		p = points[48:68]  # 嘴唇点集分布
		img2 = red_lip(img, p, color)
		# color: 调节嘴唇的颜色深度

		cv2.imshow("img", img)
		cv2.imshow('img1', img1)
		cv2.imshow("out_put", img2)
		cv2.waitKey(1)


在这里插入图片描述

这个效果就很明显了,可能小伙伴们觉得颜色不够红,这里给小伙伴们提供一个方法就是,在增加一个TrackBar用来控制红色的透明度,小伙伴们还可以多添加几个TrackBar用来改变嘴唇的颜色,这里就不写了,交由小伙伴们自行发挥。

(五)放大眼睛(局部缩放算法)

这里我所以左右眼的最左点与最点的中点为中心进行缩放的,小伙伴们也可以用左右眼的上下斜对角点看看,其中下面代码中radius: 眼睛放大范围半径 strength:眼睛放大程度。

import numpy as np
import dlib
import cv2
import math



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

def bilinear_insert(image, new_x, new_y):
    """
    双线性插值法
    """
    w, h, c = image.shape
    if c == 3:
        x1 = int(new_x)
        x2 = x1 + 1
        y1 = int(new_y)
        y2 = y1 + 1

        part1 = image[y1, x1].astype(np.float) * (float(x2) - new_x) * (float(y2) - new_y)
        part2 = image[y1, x2].astype(np.float) * (new_x - float(x1)) * (float(y2) - new_y)
        part3 = image[y2, x1].astype(np.float) * (float(x2) - new_x) * (new_y - float(y1))
        part4 = image[y2, x2].astype(np.float) * (new_x - float(x1)) * (new_y - float(y1))

        insertValue = part1 + part2 + part3 + part4

        return insertValue.astype(np.int8)


def local_zoom_warp(image, point, radius, strength):
    """
    图像局部缩放算法
    """
    height = image.shape[0]
    width = image.shape[1]
    left =int(point[0] - radius) if point[0] - radius >= 0 else 0
    top = int(point[1] - radius) if point[1] - radius >= 0 else 0
    right = int(point[0] + radius) if point[0] + radius < width else width-1
    bottom = int(point[1] + radius) if point[1] + radius < height  else height-1

    radius_square = math.pow(radius, 2)
    for y in range(top, bottom):
        offset_y = y - point[1]
        for x in range(left, right):
            offset_x = x - point[0]
            dist_xy = offset_x * offset_x + offset_y * offset_y

            if dist_xy <= radius_square:
                scale = 1 - dist_xy / radius_square
                scale = 1 - strength / 100 * scale
                new_x = offset_x * scale + point[0]
                new_y = offset_y * scale + point[1]
                new_x = new_x if new_x >=0 else 0
                new_x = new_x if new_x < height-1 else height-2
                new_y = new_y if new_y >= 0 else 0
                new_y = new_y if new_y < width-1 else width-2

                image[y, x] = bilinear_insert(image, new_x, new_y)

def empty(a):
    pass

cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars", 650, 70)
cv2.createTrackbar("radius", "TrackBars", 0, 100, empty)  # 这里设置dist_left最大值为100
cv2.createTrackbar("strength", "TrackBars", 0, 100, empty)  # 这里设置dist_right最大值为100

while True:

	img=cv2.imread('1.jpg')
	img1=img.copy()
	img2=img.copy()

	gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

	# 检测人脸
	rects = detector(gray, 0)

	# 遍历每一个检测到的人脸
	for rect in rects:
		# 获取坐标
		result = predictor(gray, rect)
		result=result.parts()
		points = [[p.x, p.y] for p in result]
		#print(type(points))#类型为list


		points=np.array(points)#这里需将上面的points转化为数组
		#print(points)

		for (x, y) in points[:]:
			# print(rects.parts())
			cv2.circle(img1, (x, y), 3, (0, 255, 0), -1)  # 还是原谅色

		# 以左眼最左点和最右点之间的中点为圆心
		left_eye_top = points[42]
		left_eye_bottom = points[46]
		left_eye_center = (left_eye_top + left_eye_bottom) / 2
		# 以右眼最左点和最右点之间的中点为圆心
		right_eye_top = points[36]
		right_eye_bottom = points[40]
		right_eye_center = (right_eye_top + right_eye_bottom) / 2


		# 放大双眼
		radius=cv2.getTrackbarPos("radius", "TrackBars")
		strength=cv2.getTrackbarPos("strength", "TrackBars")
		local_zoom_warp(img2, left_eye_center, radius=radius, strength=strength)
		local_zoom_warp(img2, right_eye_center, radius=radius, strength=strength)
		#radius: 眼睛放大范围半径 strength:眼睛放大程度

		cv2.imshow("img", img)
		cv2.imshow('img1',img1)
		cv2.imshow("out_put",img2)
		cv2.waitKey(1)

在这里插入图片描述

这里小伙伴们可能看不出明显效果,但是效果还是有的,因为我在拖动Trackbars可以明显的看到眼睛变大的过程,当然这里面还有很多需要优化的地方,就不细说了

(六)备注

最近忙于炼丹,等后面有时间就开始写一些关于视觉方面的深度学习相关的例程,还有就是下次可能会写一个简单的头部姿态估计

(七)结语

学习opencv有很多的方法,我的建议是你可以加一些群,可以充分利用B站,CSDN,和百度。

在我的博客中,我不会讲解opencv的算法实现(当然我也不太会),我只会讲解一些函数的调用,不理解就多改一些参数,多尝试尝试,慢慢你就理解来。相信你总有一天可以说opencv不过“Ctrl+C,Crtl+V”

如果有什么错误的地方,还请大家批评指正,最后,希望小伙伴们都能有所收获。
在这里插入图片描述

  • 6
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值