利用opencv进行简易的拍照并处理照片
阅读原文时间:2021年11月21日阅读:1

今天用python写了一个调用摄像头拍照并对图片进行素描化或动漫化的小demo。

首先我的环境是:PyCharm+python3.8+opencv-python(4.4.0.42)

我们分析一下思路,第一步应该是调用我们的摄像头拍取照片并保存到一个文件夹,第二步是读取文件夹中的照片,把照片变成素描化或者动漫化。

下面就开始一步步实现:

第一步:

1.导入我们要用到的模块

#导入模块
import cv2
from PIL import Image, ImageOps, ImageFilter

2.初始化我们的摄像头

#摄像头
    cap = cv2.VideoCapture(0)#这里如果你是默认的摄像头,那么就是0,否则你要取1

3.检测我们的摄像头是否在开启状态,并得到每一帧的图像效果;这里对照片每一帧的截取我用的是通过检测键盘按键来识别,如下:

 num = 1
    while(cap.isOpened()):#检测是否在开启状态
        ret_flag,Vshow = cap.read()#得到每帧图像
        cv2.imshow("Capture_Test",Vshow)#显示图像
        k = cv2.waitKey(1) & 0xFF#按键判断
        if k == ord('s'):#保存
            cv2.imwrite('D:/MyShare/test_img/'+str(num)+".jpg",Vshow)#保存路径
            print("success to save "+str(num)+".jpg")
            print("-------------------------")
            num += 1
        elif k == ord(' '):#空格退出
            break

4.根据上面的三步,我们就保存了我们摄像头截取的照片,那么我们不再使用摄像头就应该把摄像头关闭,防止它一直占用我们的资源同时也要释放内存。

  #释放摄像头
    cap.release()
    #释放内存
    cv2.destroyAllWindows()

这样我们就把第一步给完成了。

接下来,我们就来完成我们的第二步操作:

第二步:

1.编写把照片转成漫画风格的函数,里面用到了高斯金字塔取样,双边滤波,模糊,增强边缘效果。这些我们都可以去网上百度到,那么我们就不在这里进行讨论了,具体的参数是可以自己去调试的,我这里只给我的参数。那么直接上代码:

#转成漫画风格
def toCarttonStyle(picturePath):
    #设置输入输出路径和文件名称
    imgInput_FileName = picturePath
    imgOutput_FileName = picturePath.split(".")[0] + '_cartoon.' + picturePath.split(".")[1]
    # imgOutput_FileName = picturePath

    #属性设置
    num_down = 2 #缩减像素采样的数目
    num_bilateral = 7 #定义双边滤波的数目

    #读取图片
    img_rgb = cv2.imread(imgInput_FileName)
    #img_rgb = cv2.imdecode(np.fromfile(imgInput_FileName, dtype=np.uint8), cv2.IMREAD_COLOR)

    #用高斯金字塔降低取样
    img_color = img_rgb
    for _ in range(num_down):
        img_color = cv2.pyrDown(img_color)

    #重复使用小的双边滤波代替一个大的滤波
    for _ in range(num_bilateral):
        img_color = cv2.bilateralFilter(img_color,d=9,sigmaColor=9,sigmaSpace=7)

    #升采样图片到原始大小
    for _ in range(num_down):
        img_color = cv2.pyrUp(img_color)

    #转换为灰度并且使其产生中等的模糊
    img_gray = cv2.cvtColor(img_rgb,cv2.COLOR_BGR2GRAY)
    img_blur = cv2.medianBlur(img_gray,7)

    #检测到边缘并且增强其效果
    img_edge = cv2.adaptiveThreshold(img_blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,blockSize=9,C=2)

    #算法处理后,照片的尺寸可能会不统一
    #把照片的尺寸统一化
    height = img_rgb.shape[0]
    width = img_rgb.shape[1]
    img_color = cv2.resize(img_color,(width,height))

    # 转换回彩色图像
    img_edge = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2RGB)
    img_cartoon = cv2.bitwise_and(img_color, img_edge)

    # 保存转换后的图片
    cv2.imwrite(imgOutput_FileName, img_cartoon)
    print('文件转换成漫画成功,保存在' + imgOutput_FileName)

2.把照片转成素描风格,这里我们肯定是要先把照片进行一个透明度转换,再接下来就是把照片的色彩改成灰色(你也可以改成你想要的颜色),然后再把照片进行模糊度的处理,就转成了简单的素描风格。

透明度转换:

#透明度转换,素描转换的一部分
def dodge(a,b,alpha):
    #alpha为图片透明度
    return min(int(a * 255 /(256 - b * alpha)),255)

图像转成素描:

#图片转换为素描
def toSketchStyle(picturePath,blur=25,alpha=1.0):
    # 设置输入输出路径和文件名称
    imgInput_FileName = picturePath
    imgOutput_FileName = picturePath.split(".")[0] + '_Sketch.' + picturePath.split(".")[1]
    # imgOutput_FileName = picturePath

    #转化成ima对象
    img = Image.open(picturePath)
    #将文件转成灰色
    img1 = img.convert('L')
    img2 = img1.copy()
    img2 = ImageOps.invert(img2)

    #模糊度
    for i in range(blur):
        img2 = img2.filter(ImageFilter.BLUR)
    width,height = img1.size
    for x in range(width):
        for y in range(height):
            a = img1.getpixel((x,y))
            b = img2.getpixel((x,y))
            img1.putpixel((x,y),dodge(a,b,alpha))

    #保存转换后文件
    img1.save(imgOutput_FileName)
    print('文件转换成漫画成功,保存在' + imgOutput_FileName)

这样就把第二步完成了。下面我把全部的代码展示出来:

#导入模块
import cv2
from PIL import Image, ImageOps, ImageFilter

def camera():
    #摄像头
    cap = cv2.VideoCapture(0)#这里如果你是默认的摄像头,那么就是0,否则你要取1

    flag = 1

    num = 1
    while(cap.isOpened()):#检测是否在开启状态
        ret_flag,Vshow = cap.read()#得到每帧图像
        cv2.imshow("Capture_Test",Vshow)#显示图像
        k = cv2.waitKey(1) & 0xFF#按键判断
        if k == ord('s'):#保存
            cv2.imwrite('D:/MyShare/test_img/'+str(num)+".jpg",Vshow)#保存路径
            print("success to save "+str(num)+".jpg")
            print("-------------------------")
            num += 1
        elif k == ord(' '):#空格退出
            break

    #释放摄像头
    cap.release()
    #释放内存
    cv2.destroyAllWindows()

#转成漫画风格
def toCarttonStyle(picturePath):
    #设置输入输出路径和文件名称
    imgInput_FileName = picturePath
    imgOutput_FileName = picturePath.split(".")[0] + '_cartoon.' + picturePath.split(".")[1]
    # imgOutput_FileName = picturePath

    #属性设置
    num_down = 2 #缩减像素采样的数目
    num_bilateral = 7 #定义双边滤波的数目

    #读取图片
    img_rgb = cv2.imread(imgInput_FileName)
    #img_rgb = cv2.imdecode(np.fromfile(imgInput_FileName, dtype=np.uint8), cv2.IMREAD_COLOR)

    #用高斯金字塔降低取样
    img_color = img_rgb
    for _ in range(num_down):
        img_color = cv2.pyrDown(img_color)

    #重复使用小的双边滤波代替一个大的滤波
    for _ in range(num_bilateral):
        img_color = cv2.bilateralFilter(img_color,d=9,sigmaColor=9,sigmaSpace=7)

    #升采样图片到原始大小
    for _ in range(num_down):
        img_color = cv2.pyrUp(img_color)

    #转换为灰度并且使其产生中等的模糊
    img_gray = cv2.cvtColor(img_rgb,cv2.COLOR_BGR2GRAY)
    img_blur = cv2.medianBlur(img_gray,7)

    #检测到边缘并且增强其效果
    img_edge = cv2.adaptiveThreshold(img_blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,blockSize=9,C=2)

    #算法处理后,照片的尺寸可能会不统一
    #把照片的尺寸统一化
    height = img_rgb.shape[0]
    width = img_rgb.shape[1]
    img_color = cv2.resize(img_color,(width,height))

    # 转换回彩色图像
    img_edge = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2RGB)
    img_cartoon = cv2.bitwise_and(img_color, img_edge)

    # 保存转换后的图片
    cv2.imwrite(imgOutput_FileName, img_cartoon)
    print('文件转换成漫画成功,保存在' + imgOutput_FileName)

#透明度转换,素描转换的一部分
def dodge(a,b,alpha):
    #alpha为图片透明度
    return min(int(a * 255 /(256 - b * alpha)),255)

#图片转换为素描
def toSketchStyle(picturePath,blur=25,alpha=1.0):
    # 设置输入输出路径和文件名称
    imgInput_FileName = picturePath
    imgOutput_FileName = picturePath.split(".")[0] + '_Sketch.' + picturePath.split(".")[1]
    # imgOutput_FileName = picturePath

    #转化成ima对象
    img = Image.open(picturePath)
    #将文件转成灰色
    img1 = img.convert('L')
    img2 = img1.copy()
    img2 = ImageOps.invert(img2)

    #模糊度
    for i in range(blur):
        img2 = img2.filter(ImageFilter.BLUR)
    width,height = img1.size
    for x in range(width):
        for y in range(height):
            a = img1.getpixel((x,y))
            b = img2.getpixel((x,y))
            img1.putpixel((x,y),dodge(a,b,alpha))

    #保存转换后文件
    img1.save(imgOutput_FileName)
    print('文件转换成漫画成功,保存在' + imgOutput_FileName)

if __name__ == '__main__':
    camera()
    imgInput_FileName = input('输入文件路径: ')
    while True:
        print('1、漫画风格')
        print('2、素描风格')
        userChoose = input('请选择风格(输入序号即可):')
        if userChoose.__eq__('1'):
            toCarttonStyle(imgInput_FileName)
            break
        elif userChoose.__eq__('2'):
            toSketchStyle(imgInput_FileName)
            break
        else:
            print('违法输入(请输入序号)')
            break

我放一张运行的展示图:

运行成功以后,你就可以去你的文件夹看看照片了。

下面的链接是关于高斯金字塔,滤波和模糊度:

https://www.cnblogs.com/wj-1314/p/11981974.html

https://zhuanlan.zhihu.com/p/279602383

https://www.cnblogs.com/april0315/p/13716651.html

本人水平有限,如有错误,可以来纠正我,欢迎大家进行交流。