Python制作抖音同款含褶皱面料图

写在前面的话。

之前在码友slandarer的CSDN主页https://blog.csdn.net/slandarer看到他用MATLAB实现了几个有趣的图片处理趣案例,一时技痒,斗胆留言我也要用python跟帖。

今天兑现诺言,小试牛刀,就从“Python制作抖音同款含褶皱面料图”开始吧,有兴趣的同学可以先看slandarer的原帖https://blog.csdn.net/slandarer/article/details/115709803

这是我第一次在CSDN发帖,有不当的地方请各位大神轻拍指正。

为方便大家对比学习两种语言的实现方法,以下基本仿照原帖行文结构展开。

 

先看效果!!

Python制作抖音同款含褶皱面料图_第1张图片

 

                                                                                                                                                       右下角原帖图像的水印都还在

步骤

0.当一个称职的调包贼

要用到numpy和opencv两个站点包。当然,要说明的是,我使用的是python3.7.6环境,编辑器推荐Anaconda3,需要的请自行移步清华大学镜像源下载。

Anaconda3自带numpy包,opencv需要自行安装,方法:在命令提示行键入pip install opencv-python,回车,坐等安装完毕即可。

# -*- coding: utf-8 -*-
"""
Created on Sat Apr 24 22:55:24 2021
@author: ck
"""
import numpy as np
import cv2

1.导入图片

导入褶皱图片(background.jpg)作为背景图像,蒙皮图片(foreground.jpg)作为前景;将褶皱图片灰度化,将前景图调整至与褶皱图片相同大小:

#1.读取背景和前景图像
bimg = cv2.imread('background.jpg')
bgray = cv2.cvtColor(bimg, cv2.COLOR_BGR2GRAY).astype(np.int)
fimg0 = cv2.imread('foreground.jpg')
fimg = cv2.resize(fimg0, dsize = bgray.shape, interpolation=cv2.INTER_NEAREST).astype(np.int)

background.jpg

Python制作抖音同款含褶皱面料图_第2张图片

foreground.jpg

Python制作抖音同款含褶皱面料图_第3张图片

2.图片扩张

因为我们要对前景图片进行拉伸,难免边角处缺一块,因此我们首先将边缘处颜色往外扩展几圈(13圈)

代码:

#2.构造扩展的前景图像(扩大13圈)
Y,X,N = fimg.shape
exfimg = np.zeros((Y+26,X+26,N))
exfimg[13:-13, 13:-13, :] = fimg#中心
for i in range(13):#左右,不含四角
    exfimg[13:-13, i, :] = fimg[:,0,:]#左
    exfimg[13:-13, -i-1, :] = fimg[:,-1,:]#右
for i in range(13):#上下,含四角
    exfimg[i, :, :] = exfimg[13,:,:]#上
    exfimg[-i-1, :, :] = exfimg[-14,:,:]#下    

效果:

Python制作抖音同款含褶皱面料图_第4张图片

3.像素映射

(本部分文字说明部分除括号里部分,全部来自slandarer原帖,因为我实在没有参透扭曲置换的原理到底是啥,所以这部分只当了数学处理过程的搬运工)
原理借鉴ps扭曲置换的原理,亮度较大的像素(大于128)取右下角像素RGB值进行置换,亮度较小的像素(小于128)取左上角像素RGB值进行置换,由于
(255-128)/10=12.7
(0-128)/10=-12.8
各个像素点与替换像素点的距离不超过13(看slandarer给出的代码,我觉得这里应该是26,替换像素点在原像素点右下45°方向距离26范围以内),因此上一步共扩展了13圈。
同时因为各个像素分布为整数点位置,而位置差计算一般都不是整数,因此我们要对偏移距离向上向下取整,获得两个像素点RGB值,并对这两点数值进行线性插值即可

代码:

#3.像素映射
goffset = (bgray - 128)/10
offsetLim1 = (np.floor(goffset) + 13).astype(np.int)
offsetLim2 = (np.ceil(goffset) + 13).astype(np.int)
sep1 = (goffset - np.floor(goffset)).flatten()
sep2 = (np.ceil(goffset) - goffset).flatten()
XX, YY = np.meshgrid(range(exfimg.shape[0]-26),range(exfimg.shape[1]-26))
XX1, YY1 = XX + offsetLim1, YY + offsetLim1#向下取整坐标矩阵
XX2, YY2 = XX + offsetLim2, YY + offsetLim2#向上取整坐标矩阵
c1 = exfimg[YY1.flatten(), XX1.flatten(), :]
c2 = exfimg[YY2.flatten(), XX2.flatten(), :]
p1 = np.where(sep1 == 0, c1[:,0], c2[:,0]*sep1.flatten() + c1[:,0]*sep2.flatten())
p2 = np.where(sep1 == 0, c1[:,0], c2[:,1]*sep1.flatten() + c1[:,1]*sep2.flatten())
p3 = np.where(sep1 == 0, c1[:,0], c2[:,2]*sep1.flatten() + c1[:,2]*sep2.flatten()) 

4.正片叠底

(同理,本部分文字全部来自slandarer原帖,我只是数学处理过程的搬运工)

将两张图片叠加起来
公式:混合色×基色 / 255=结果色
由于正片叠底后所出图片较暗,这里我们选择除以220而不是255:

代码:

#4.正片叠底
newarr = np.array([p1.reshape(bgray.shape),p2.reshape(bgray.shape),p3.reshape(bgray.shape)])
newarr = newarr*bgray/220
newarr = newarr.transpose((1,2,0)).astype(np.uint8)

5.结果保存与显示

cv2.imwrite('result.jpg', newarr)
cv2.imshow('add_result',newarr)

效果见本帖开头。

6.完整代码

# -*- coding: utf-8 -*-
"""
Created on Sat Apr 24 22:55:24 2021
@author: caokun
"""
import numpy as np
import cv2

#1.读取背景和前景图像
bimg = cv2.imread('background.jpg')
bgray = cv2.cvtColor(bimg, cv2.COLOR_BGR2GRAY).astype(np.int)
fimg0 = cv2.imread('foreground.jpg')
fimg = cv2.resize(fimg0, dsize = bgray.shape, interpolation=cv2.INTER_NEAREST).astype(np.int)
#2.构造扩展的前景图像(扩大13圈)
Y,X,N = fimg.shape
exfimg = np.zeros((Y+26,X+26,N))
exfimg[13:-13, 13:-13, :] = fimg#中心
for i in range(13):#左右,不含四角
    exfimg[13:-13, i, :] = fimg[:,0,:]#左
    exfimg[13:-13, -i-1, :] = fimg[:,-1,:]#右
for i in range(13):#上下,含四角
    exfimg[i, :, :] = exfimg[13,:,:]#上
    exfimg[-i-1, :, :] = exfimg[-14,:,:]#下    
cv2.imwrite('expandimg.jpg', exfimg)
#3.像素映射
goffset = (bgray - 128)/10
offsetLim1 = (np.floor(goffset) + 13).astype(np.int)
offsetLim2 = (np.ceil(goffset) + 13).astype(np.int)
sep1 = (goffset - np.floor(goffset)).flatten()
sep2 = (np.ceil(goffset) - goffset).flatten()
XX, YY = np.meshgrid(range(exfimg.shape[0]-26),range(exfimg.shape[1]-26))
XX1, YY1 = XX + offsetLim1, YY + offsetLim1#向下取整坐标矩阵
XX2, YY2 = XX + offsetLim2, YY + offsetLim2#向上取整坐标矩阵
c1 = exfimg[YY1.flatten(), XX1.flatten(), :]
c2 = exfimg[YY2.flatten(), XX2.flatten(), :]
p1 = np.where(sep1 == 0, c1[:,0], c2[:,0]*sep1.flatten() + c1[:,0]*sep2.flatten())
p2 = np.where(sep1 == 0, c1[:,0], c2[:,1]*sep1.flatten() + c1[:,1]*sep2.flatten())
p3 = np.where(sep1 == 0, c1[:,0], c2[:,2]*sep1.flatten() + c1[:,2]*sep2.flatten()) 
#4.正片叠底
newarr = np.array([p1.reshape(bgray.shape),p2.reshape(bgray.shape),p3.reshape(bgray.shape)])
newarr = newarr*bgray/220
newarr = newarr.transpose((1,2,0)).astype(np.uint8)
cv2.imwrite('result.jpg', newarr)
cv2.imshow('add_result',newarr)

说明:

我对前景图像拓展部分的处理逻辑做了优化,看起来要优雅一点(python本身就以优雅著称嘛);

总代码量(有效部分)比原帖略少,像素映射部分还可以精简优化,没时间搞了,有兴趣的朋友可以试试;

整体速度与原贴提供的MATLAB代码不相上下(也可能略慢)。

各位斧正。

 

你可能感兴趣的:(python图像处理,python,opencv,numpy,计算机视觉,cv)