蔡蔡子相信大家都很熟悉,他擅长唱、跳、Rap还有篮球!今天,就让我们用Opencv将蔡老师的篮球教学视频以素描的形式呈现出来。

1.安装Python的Opencv

首先我们装上Python版本的OpenCV,在命令行/终端输入

pip install opencv-python

如果是已经自带Python2.7的系统(Mac等)记得加上3:

pip3 install opencv-python

我的就是已经安装好了:

2.读取照片

安装好了Opencv后,就到了加载蔡老师照片的时候了。

先保存蔡老师的一张照片,并命名为“cxk.jpg”,并放置在与代码相同的路径下:

代码:

import cv2img_cxk = cv2.imread('cxk.jpg')
cv2.imshow('cxk', img_cxk)cv2.waitKey(0)
cv2.destroyAllWindows()

运行:

稍微解释一下上面的代码,我们利用cv2.imread('cxk.jpg')读取了这张图片,保存到img_cxk这个变量里面。

接下来用cv2.imshow('cxk', img_cxk)将这张照片通过一个窗口显示出来,并且这个窗口的名称叫做cxk。

然后我们用cv2.waitKey(0)来等待用户的按键操作,waitKey(n)里的n表示等待多少毫秒的时间,超过这个时间程序就会继续运行下去。我们把它设为0表示无限等待下去,也就是只要用户没有在这个窗口内按下任何按键,程序就会一直停在这里。

最后,当用户按下任意按键,程序执行cv2.destroyAllWindows(),把窗口都关掉,程序结束。

OK!我们继续跟着蔡老师一起打篮球!

3.彩色图片转成灰度图

接下来我们要把彩色图片转换成灰度图:

import cv2img_cxk = cv2.imread('cxk.jpg')
cv2.imshow('cxk', img_cxk)img_gray = cv2.cvtColor(img_cxk, cv2.COLOR_RGB2GRAY)
cv2.imshow('gray', img_gray)cv2.waitKey(0)
cv2.destroyAllWindows() 

没错,将彩色RGB图片转换成灰度图用

cv2.cvtColor(img_cxk, cv2.COLOR_RGB2GRAY)

就可以啦。但是要注意这里我们用的是cv2.COLOR_RGB2GRAY,对于一些老版本的OpenCV或者其他模块可能还是采用BGR的通道顺序,也就是cv2.COLOR_BGR2GRAY,这里如果出问题了记得看看是不是彩色通道顺序问题。

上面这段代码执行后我们就多了一个窗口,里面显示的是灰色的蔡老师:

4.对灰度图进行高斯模糊

接下来让我们对这张灰度图进行高斯模糊:

import cv2#加载照片
img_cxk = cv2.imread('cxk.jpg')
cv2.imshow('cxk', img_cxk)#灰度图
img_gray = cv2.cvtColor(img_cxk, cv2.COLOR_RGB2GRAY)
cv2.imshow('gray', img_gray)#高斯模糊
img_blurred = cv2.GaussianBlur(img_gray, (5, 5), 0)
cv2.imshow('blurred', img_blurred)cv2.waitKey(0)
cv2.destroyAllWindows()

在这里,我们用

cv2.GaussianBlur(img_gray, (5, 5), 0)

完成了图像的高斯模糊,那么模糊效果是如何实现的呢?其实很简单,我们从最简单的模糊效果说起,假设图片中有一块区域如下:

我们要对中间5这个像素进行模糊,最简单的方式就是直接和周围八个像素一起取平均值嘛!中间值=(8*1+5)/9=1.44444……

高斯模糊也是类似,只不过不是简单的取平均值,而是通过高斯函数计算对应的数值,有兴趣的话可以去了解,这里就不多解释啦。

那么我们在

cv2.GaussianBlur(img_gray, (5, 5), 0)

中使用的(5,5)参数就表示高斯核的尺寸,这个核尺寸越大图像越模糊。但是记住尺寸得是奇数!这是为了保证中心位置是一个像素而不是四个像素。

这样我们就得到一个模糊的蔡老师(通过对比可以看出确实模糊了):

尺寸换成(15,15),图片就更加模糊了:

5.图像二值化

接下来到关键的一步啦!让我们对这张模糊过的图片进行二值化:

import cv2#加载照片
img_cxk = cv2.imread('cxk.jpg')
cv2.imshow('cxk', img_cxk)#灰度图
img_gray = cv2.cvtColor(img_cxk, cv2.COLOR_RGB2GRAY)
cv2.imshow('gray', img_gray)#高斯模糊
img_blurred = cv2.GaussianBlur(img_gray, (15, 15), 0)
cv2.imshow('blurred', img_blurred)#图像二值化
img_threshold1 = cv2.adaptiveThreshold(img_blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 2)
cv2.imshow('img_threshold1', img_threshold1)cv2.waitKey(0)
cv2.destroyAllWindows()

二值化的概念其实很简单,就是对一张图片上的点,像素值大于等于某个值的都直接设为最大值,小于这个值的都直接设为最小值,这样这张图片上每个点都只可能是最大值或最小值其中之一了,其中我们比较的这个数值就是阈值。

当然如果对整张图片都规定同一个阈值,可能会出现下图右上的效果,因为实际图片还有阴影之类的问题会影响,这样就出

现了自适应二值化的方法,如下图下排两张图。

在代码中我们用cv2.adaptiveThreshold()来实现这种自适应二值化方法。其中参数255表示我们二值化后图像的最大值,cv2.ADAPTIVE_THRESH_GAUSSIAN_C表示我们采用的自适应方法,cv2.THRESH_BINARY表示我们是将大于阈值的像素点的值变成最大值,反之这里如果使用cv2.THRESH_BINARY_INV表示我们是将大于阈值的像素点的值变成0,倒数第二个参数5表示我们用多大尺寸的区块来计算阈值,倒数第一个参数2表示计算周边像素点均值时待减去的常数C。

运行后就可以得到一个二值化的蔡老师:

6.再次对二值化图像进行模糊

由于采用了自适应二值化的方法,原本深色衣服的地方也自适应地变成了白色,实现了一个简单描边效果。现在我们已经初步实现了素描效果,但是还不够,让我们继续完善一下,让边线更宽,噪点更少一些。

import cv2#加载照片
img_cxk = cv2.imread('cxk.jpg')
cv2.imshow('cxk', img_cxk)#灰度图
img_gray = cv2.cvtColor(img_cxk, cv2.COLOR_RGB2GRAY)
cv2.imshow('gray', img_gray)#高斯模糊
img_blurred = cv2.GaussianBlur(img_gray, (5, 5), 0)
cv2.imshow('blurred', img_blurred)#图像二值化
img_threshold1 = cv2.adaptiveThreshold(img_blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 2)
cv2.imshow('img_threshold1', img_threshold1)#再次模糊
img_threshold1_blurred = cv2.GaussianBlur(img_threshold1, (5, 5), 0)
cv2.imshow('img_threshold1_blurred', img_threshold1_blurred)cv2.waitKey(0)
cv2.destroyAllWindows()

和刚才一样我们用cv2.GaussianBlur()完成了高斯模糊,这样我们就可以得到一个模糊的描边蔡老师:

7.再次进行二值化

接下来我们对这张图片再次进行二值化:

import cv2#加载照片
img_cxk = cv2.imread('cxk.jpg')
cv2.imshow('cxk', img_cxk)#灰度图
img_gray = cv2.cvtColor(img_cxk, cv2.COLOR_RGB2GRAY)
cv2.imshow('gray', img_gray)#高斯模糊 尺寸越大就越模糊
img_blurred = cv2.GaussianBlur(img_gray, (5, 5), 0)
cv2.imshow('blurred', img_blurred)#图像二值化
img_threshold1 = cv2.adaptiveThreshold(img_blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 2)
cv2.imshow('img_threshold1', img_threshold1)#再次模糊
img_threshold1_blurred = cv2.GaussianBlur(img_threshold1, (5, 5), 0)
cv2.imshow('img_threshold1_blurred', img_threshold1_blurred)#再次二值化
_, img_threshold2 = cv2.threshold(img_threshold1_blurred, 200, 255, cv2.THRESH_BINARY)
cv2.imshow('img_threshold2', img_threshold2)cv2.waitKey(0)
cv2.destroyAllWindows()

和刚才不一样的是,由于这张图片已经比较干净没有什么阴影,我们直接采用最简单的二值化方法

cv2.threshold(img_threshold1_blurred, 200, 255, cv2.THRESH_BINARY)。其中200表示将图片中像素值为200以上的点都变成255,255就是白色。这样我们就能得到一个边线更宽的二值化效果:

8.图像开运算

下面让我们去掉图片中一些细小的噪点,这种效果可以通过图像的开运算来实现:

import cv2#加载照片
img_cxk = cv2.imread('cxk.jpg')
cv2.imshow('cxk', img_cxk)#灰度图
img_gray = cv2.cvtColor(img_cxk, cv2.COLOR_RGB2GRAY)
cv2.imshow('gray', img_gray)#高斯模糊 尺寸越大就越模糊
img_blurred = cv2.GaussianBlur(img_gray, (5, 5), 0)
cv2.imshow('blurred', img_blurred)#图像二值化
img_threshold1 = cv2.adaptiveThreshold(img_blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 2)
cv2.imshow('img_threshold1', img_threshold1)#再次模糊
img_threshold1_blurred = cv2.GaussianBlur(img_threshold1, (5, 5), 0)
cv2.imshow('img_threshold1_blurred', img_threshold1_blurred)#再次二值化
_, img_threshold2 = cv2.threshold(img_threshold1_blurred, 200, 255, cv2.THRESH_BINARY)
cv2.imshow('img_threshold2', img_threshold2)kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
img_opening = cv2.bitwise_not(cv2.morphologyEx(cv2.bitwise_not(img_threshold2), cv2.MORPH_OPEN, kernel))
cv2.imshow('img_opening', img_opening)cv2.waitKey(0)
cv2.destroyAllWindows()

要理解图像的开运算就要知道图像的腐蚀和膨胀,所谓的图像腐蚀就是如下的操作,类似于把一个胖子缩小一圈变瘦的感觉:

图像膨胀就是腐蚀的反向操作,把图像中的区块变大一圈,把瘦子变成胖子。

因此当我们对一个图像先腐蚀再膨胀的时候,一些小的区块就会由于腐蚀而消失,再膨胀回来的时候大块区域的边线的宽度没有发生变化,这样就起到了消除小的噪点的效果。图像先腐蚀再膨胀的操作就叫做开运算。

回到我们的代码,首先开运算要有一个运算的核,我们通过:

kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))

可以得到一个3*3的核。

然后通过

cv2.morphologyEx(cv2.bitwise_not(img_threshold2), cv2.MORPH_OPEN, kernel)

来进行图像的开运算。

这里需要注意的是我们没有直接对img_threshold2进行开运算,而是对cv2.bitwise_not(img_threshold2)进行运算,那么cv2.bitwise_not(img_threshold2)又是干啥的呢?

cv2.bitwise_not()其实就是对图像进行一个简单的操作,原来是0的像素点变成最大值,原来是最大值的像素点变成0。相当于黑色的地方变成白色,白色的地方变成黑色。

那么为什么我们要把图像反色一下再进行开运算呢?首先要知道图像中一般0表示黑色,255表示白色,我们看到的大片的白色底少部分黑色线其实从数值上来看是图片大部分地方是255少部分地方是0。但是开运算的操作是对有数值的地方进行缩小,这样就必须先将图片反色一下,使得大部分地方是0而少部分线的地方是255,然后再进行开运算就能得到正确的结果了。

这样我们就得到一个更少噪点蔡老师啦:

9.第三次对图像进行高斯模糊

接下来我们对这张二值化的图像再简单进行高斯模糊,让图片更接近素描的效果。

import cv2#加载照片
img_cxk = cv2.imread('cxk.jpg')
cv2.imshow('cxk', img_cxk)#灰度图
img_gray = cv2.cvtColor(img_cxk, cv2.COLOR_RGB2GRAY)
cv2.imshow('gray', img_gray)#高斯模糊 尺寸越大就越模糊
img_blurred = cv2.GaussianBlur(img_gray, (5, 5), 0)
cv2.imshow('blurred', img_blurred)#图像二值化
img_threshold1 = cv2.adaptiveThreshold(img_blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 2)
cv2.imshow('img_threshold1', img_threshold1)#再次模糊
img_threshold1_blurred = cv2.GaussianBlur(img_threshold1, (5, 5), 0)
cv2.imshow('img_threshold1_blurred', img_threshold1_blurred)#再次二值化
_, img_threshold2 = cv2.threshold(img_threshold1_blurred, 200, 255, cv2.THRESH_BINARY)
cv2.imshow('img_threshold2', img_threshold2)#开运算
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
img_opening = cv2.bitwise_not(cv2.morphologyEx(cv2.bitwise_not(img_threshold2), cv2.MORPH_OPEN, kernel))
cv2.imshow('img_opening', img_opening)#第三次高斯模糊
img_opening_blurred = cv2.GaussianBlur(img_opening, (3, 3), 0)
cv2.imshow('img_opening_blurred', img_opening_blurred)cv2.waitKey(0)
cv2.destroyAllWindows()

这样下来我们就可以实现对一张彩色图片转换成素描的效果啦:

10.读取并处理视频中的图像

搞定了单张图片,对视频进行处理就非常简单了,只需要将视频里每一帧都做同样的处理再输出即可。

首先在开头位置加上读取视频的语句:

cap = cv2.VideoCapture('cxk.mp4')

然后创建一个while循环,将图像处理的语句都放进去:

while True:ret, frame = cap.read()if frame is None:breakimg_gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)img_blurred = cv2.GaussianBlur(img_gray, (5, 5), 0)img_threshold1 = cv2.adaptiveThreshold(img_blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 2)img_threshold1_blurred = cv2.GaussianBlur(img_threshold1, (5, 5), 0)_, img_threshold2 = cv2.threshold(img_threshold1_blurred, 200, 255, cv2.THRESH_BINARY)kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))img_opening = cv2.bitwise_not(cv2.morphologyEx(cv2.bitwise_not(img_threshold2), cv2.MORPH_OPEN, kernel))img_opening_blurred = cv2.GaussianBlur(img_opening, (3, 3), 0)cv2.imshow('img_opening_blurred', img_opening_blurred)if cv2.waitKey(40) & 0xFF == ord('q'):break

其中,cap.read()用来读取视频每一帧的数据,每一次调用就读取一帧图像,当读取到的frame是None时就说明视频结束,可以直接退出while循环。

在while循环的最后我们用cv2.waitKey(40) & 0xFF == ord('q')来判断用户有没有按下键盘上的q键,如果按下了就直接退出while循环。

而cv2.waitKey(40)中我们填40表示等待40毫秒,也就相当于每两张图片之间间隔40毫秒,即25帧/秒。

最后,完整的代码如下:

import cv2cap = cv2.VideoCapture('cxk.mp4')while True:ret, frame = cap.read()if frame is None:breakimg_gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)img_blurred = cv2.GaussianBlur(img_gray, (5, 5), 0)img_threshold1 = cv2.adaptiveThreshold(img_blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 5, 2)img_threshold1_blurred = cv2.GaussianBlur(img_threshold1, (5, 5), 0)_, img_threshold2 = cv2.threshold(img_threshold1_blurred, 200, 255, cv2.THRESH_BINARY)kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))img_opening = cv2.bitwise_not(cv2.morphologyEx(cv2.bitwise_not(img_threshold2), cv2.MORPH_OPEN, kernel))img_opening_blurred = cv2.GaussianBlur(img_opening, (3, 3), 0)cv2.imshow('img_opening_blurred', img_opening_blurred)if cv2.waitKey(40) & 0xFF == ord('q'):breakcv2.destroyAllWindows()

最后,我们就完成了素描版的鸡你太美!

参考文章:蔡徐坤教你用OpenCV实现素描效果 - 知乎

Opencv实现素描的坤坤打篮球相关推荐

  1. C语言书写推箱子(坤坤版easyx库)

    C语言书写推箱子(坤坤版easyx库) 游戏效果的展示 运用的知识点(必看) 代码的讲解 游戏地图的实现 地图的初始化 地图图片的加载 地图图片的放置 人物和箱子的移动(重点) 游戏结束的判断 音乐的 ...

  2. C++函数 【鸡】 坤坤带你拿下

    大家共勉,一起拿下C++函数 一.函数的本质 函数其实很好理解,他就将一段经常使用的代码封装起来,减少重复. 就像我们用鸡代替我们的偶像,介绍不必要的重复!!! 二. 函数的定义 函数的定义一般主要有 ...

  3. 我们是ikun,为坤坤加油(简单的python反序列化、爬虫、越权、支付漏洞)

    题目来源:BUUCTF: CISCN2019 华北赛区 在某个深夜,身为ikun的文打开了BUUCTF,想看看有没有同为ikun的朋友,经过简单的搜索,发现竟然真的有ikun出的题目,看到这里身为ik ...

  4. 坤坤老师告诉同学们什么是观察者模式

    观察者模式 什么是观察者模式? 观察者模式即一个对象被多个对象所依赖,当被依赖的对象发生更新时,会自动通知所有依赖的对象. 例如:微博上的坤坤老师,当坤坤老师在微博发文章时,会自动通知所有的粉丝. 坤 ...

  5. Springboot毕设项目坤坤网上商城0573k(java+VUE+Mybatis+Maven+Mysql)

    Springboot毕设项目坤坤网上商城0573k(java+VUE+Mybatis+Maven+Mysql) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBui ...

  6. 纯css实现坤坤经典动作-“铁山靠”

    背景 2023年2月16日,晴,今天没有工作,一直在掘金摸鱼,摸的我好累. 不行!我得找点有意义的事情做! 此时间,我发的一条沸点竟然有小黑子给我评论,\ 我看到之后气不打一处来,哥哥这么努力,还有这 ...

  7. 云开发坤坤鸡乐盒微信小程序源码

    云开发坤坤鸡乐盒微信小程序源码是由坤坤铁粉ikun们发布的一款专为ios系统的用户因无法下载软件版坤坤鸡乐盒而开发的小程序版, 源码下载:云开发坤坤鸡乐盒微信小程序源码-小程序文档类资源-CSDN下载

  8. 2022最新坤坤鸡乐盒微信小程序源码+云开发的

    正文: 云开发坤坤鸡乐盒微信小程序源码是由坤坤铁粉ikun们开发的. 因部分ios用户无法体验共举办,特地开发的小程序版鸡乐盒,听说作者也是5年的铁粉. 现在特别火,我也就不多作介绍了,点击就可以发出 ...

  9. 2022抖音直播云蹦迪软件程序坤坤版+文档教程

    正文: 之前分享过普通版的云蹦迪程序,今天给大家找了一下坤坤版的,坤坤是什么我就不必多说了,总之是跟之前的一个梗有关系,什么"鸡你太美". 这次我分享的除了坤坤版,普通版的云蹦迪我 ...

最新文章

  1. 内存数据库MemSQL ——基于内存,MVCC+哈希表、跳表
  2. 备战秋招 |《百面机器学习》算法+leetcode开班报名!
  3. leetcode——242. 有效的字母异位词
  4. 【python核心编程】第六章 序列
  5. 用matalb、python画聚类结果图
  6. 分治法——查找问题 —— 寻找一个序列中第k小的元素和查找最大和次大元素
  7. mysql 6位随机数_MySQL生成固定位数的随机数
  8. python编程的区别_Python与其它编程语言的区别
  9. word怎么加入html,Word中怎么放入html
  10. 拔丝芋头的Java学习日记---Day10
  11. 只会画火柴人?手残怎样开始学画画?
  12. html的时间格式转换为本地时间,将UTC日期字符串转为本地时间字符串,如@yyyy-MM-dd'T'HH:mm:ssZ转换为本地时间...
  13. SD-销售订单数量修改需大于已交货数量,消息报错而非警告调整
  14. 【红帽入门指南】第二期:Linux的基本使用
  15. 本文出自沉默王二的博客,转载必须注明出处。技术交流群 120926808
  16. Android-PullToRefresh代码分析
  17. Linux常用工具介绍
  18. 微信公众号关注来源统计查询谁会搞?
  19. 图像分类经典卷积神经网络—ResNet论文翻译(纯中文版)—Deep Residual Learning for Image Recognition(深度残差学习的图像识别)
  20. 仅仅有走过的路 才懂她的内容

热门文章

  1. 基于Pyhton的二维离散正弦变换(DST)及其反变换(IDST)
  2. IDC:英国脱欧对本国IT支出带来3大潜在影响
  3. java 视频转换 avi 转 MP4
  4. 总体方差、样本方差、自由度的理解
  5. 南宁富士康c语言笔试题,富士康笔试题目
  6. 小ck活动机器人包包_你一定要入手的小ck包
  7. Rio手把手教学:如何打造容器化应用程序的一站式部署体验
  8. 老夫聊发少年狂,西北望,射天狼!----马云余额宝 集团(转)
  9. VSTS Overview
  10. 【含源码】用python做游戏有多简单好玩