利用python的海龟素描出一张图片的内容

2020-08-07   283 次阅读


请注意,本文编写于  258  天前,最后编辑于  140  天前,内容可能已经不具有时效性,请谨慎参考。

摘要: 这是一篇有关利用OpenCV+turtle根据图片来绘画出一副素描画的总结。

(拖延了好久!很抱歉@_@)

其实这是我在做车牌号识别的项目中玩OpenCV产生的灵感!想着turtle竟然可以读取坐标进行画图,那我将图片的坐标让海龟自动帮我画画岂不是很好吗!哈哈哈哈哈哈哈我可真是个小天才,老资本家了(狗头)

视频效果展示:

图片效果展示:

变成

2313S1

tip: 根据[名为一无]小伙伴提出的建议做出说明:新版cv2这个库的findContours这个函数对比老版本返回值只有两个,另外优化上turtle设置成速度为0就已经是最大速度了,更快可以增加一个delay(0)以去掉绘画延迟

步骤拆解

边缘检测

image = cv2.imread(pic,0)			#读取图像
edges = cv2.Canny(image,100,200)	#进行边缘检测

在 OpenCV 中只需要一个函数:cv2.Canny(),就可以完成。 让我们看如何使用这个函数。这个函数的第一个参数是输入图像。第二和第三 个分别是 minVal 和 maxVal。第三个参数设置用来计算图像梯度的 Sobel 卷积核的大小,默认值为 3。最后一个参数是 L2gradient,它可以用来设定 求梯度大小的方程。当为False时 使用方程:Edge−Gradient(G) = |G2 x | + |G2 y | 代替,默认值为 False。

效果图:image-20200816120840476

很棒提取出来的边缘很不错的,各位可以试着调节minVal 和 maxVal来看看有什么区别!

灰度处理

img_gray = cv2.cvtColor(edges,cv2.COLOR_BAYER_BG2GRAY)

在 OpenCV 中有超过 150 中进行颜色空间转换的方法。但是你以后就会 发现我们经常用到的也就两种:BGR↔Gray 和 BGR↔HSV。 我们要用到的函数是:cv2.cvtColor(input_image,flag),其中 flag 就是转换类型。 对于 BGR↔Gray 的转换,我们要使用的 flag 就是 cv2.COLOR_BGR2GRAY。 同样对于 BGR↔HSV 的转换,我们用的 flag 就是 cv2.COLOR_BGR2HSV。

为什么已经变成黑白了还要进行灰度处理呢,这是为了更好的进行下一步(图像阈值)做准备,可以先来看看不进行灰度处理的效果:

image-20200816121319592

点分布的不均匀,提取出来的点很少,增加灰度处理可以使得下一步图像阈值更好的进行处理。

图像阈值

ret, thresh = cv2.threshold(img_gray,127,255,0)

与名字一样,这种方法非常简单。但像素值高于阈值时,我们给这个像素 赋予一个新值(可能是白色),否则我们给它赋予另外一种颜色(也许是黑色)。 这个函数就是 cv2.threshhold()。这个函数的第一个参数就是原图像,原图 像应该是灰度图。第二个参数就是用来对像素值进行分类的阈值。第三个参数 就是当像素值高于(有时是小于)阈值时应该被赋予的新的像素值。OpenCV 提供了多种不同的阈值方法,这是有第四个参数来决定的。这些方法包括:

• cv2.THRESH_BINARY

• cv2.THRESH_BINARY_INV

• cv2.THRESH_TRUNC

• cv2.THRESH_TOZERO

• cv2.THRESH_TOZERO_INV

这一步是为了提取出thresh为下一步提取坐标做准备,此处参数部分我也不是很懂,希望小伙伴可以帮我解答

提取目标轮廓坐标

#下面这句是老版本opencv的写法,如果运行报错可以将下句注释,取消下下句的注释
image,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
#contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

函数 cv2.findContours() 有三个参数,第一个是输入图像,第二个是 轮廓检索模式,第三个是轮廓近似方法。返回值有三个,第一个是图像,第二个 是轮廓,第三个是(轮廓的)层析结构。轮廓(第二个返回值)是一个 Python 列表,其中存储这图像中的所有轮廓。每一个轮廓都是一个 Numpy 数组,包 含对象边界点(x,y)的坐标。

从这里就可以发现,目标轮廓就在我们得到的contours里啦!

打印出contours会发现里面是很多的直矩阵的坐标:

image-20200816122814951

接下来我们只要提取出坐标就大功告成了!

x,y,w,h = cv2.boundingRect(contours[i])

直边界矩形 一个直矩形(就是没有旋转的矩形)。它不会考虑对象是否旋转。 所以边界矩形的面积不是最小的。可以使用函数 cv2.boundingRect() 查找得到。 (x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高。

小海龟该怎么写

其实turtle怎么写,多玩几遍就知道了,说实话我也经常忘记,但是我记得有这些步骤,我去看看语法怎么写就容易写出来(记性老差了)

def draw(xy):
    turtle.pensize(2)		#设置画笔大小
    turtle.setup(width=0.6,height=1.0)	#设置画布大小
    turtle.speed(0)	#设置速度
    for array in xy[::-1]:	
        turtle.penup()	#提起画笔
        turtle.goto((array[0]/2)-100,-(array[1]/2)+250)	#到指定坐标
        turtle.pendown()	#放下画笔
        turtle.forward(1)	#画多长长度
        print(turtle.pos())	#命令行显示出来,可以注释掉
        
    
    turtle.done()	#保留画的图

整体代码

下面是整体代码的实现

github:https://github.com/hongcyu/turtle_draw

import cv2
import numpy as np
import turtle

def array_pic(pic):
    image = cv2.imread(pic,0)
    edges = cv2.Canny(image,100,200)
    img_gray = cv2.cvtColor(edges,cv2.COLOR_BAYER_BG2GRAY)
    ret, thresh = cv2.threshold(img_gray,127,255,0)
    #下面这句是老版本opencv的写法,如果运行报错可以将下句注释,取消下下句的注释
    image,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    #contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    xy = []
    for i in range(0,len(contours)):
        x,y,w,h = cv2.boundingRect(contours[i])
        list_xy = [x,y]
        xy.append(list_xy)
    return xy
    # file = open("array.txt", mode="x")
    # file.writelines(str(contours))
    # file.close()
    # cv2.imshow("1.jpg",image)
    # cv2.waitKey(0)
    
def draw(xy):
    turtle.pensize(2)
    turtle.setup(width=0.6,height=1.0)
    turtle.speed(0)
    for array in xy[::-1]:
        turtle.penup()
        turtle.goto((array[0]/2)-100,-(array[1]/2)+250)
        turtle.pendown()
        turtle.forward(1)
        print(turtle.pos())
        
    
    turtle.done()


if __name__ == "__main__":
    pic = "image.jpg"
    xy = array_pic(pic)
    draw(xy)

注意事项:

  1. 你需要安装opencv,在cmd中输入:pip3 install opencv-python

  2. 要使用需要将图片放置在和py文件同一个文件夹下,接着修改下面的pic后的参数为图片名字。

    if __name__ == "__main__":
     	pic = "image.jpg"
     	xy = array_pic(pic)
    	 draw(xy)
    

本文由 hongCYu 创作,如果您觉得本文不错,请随意赞赏
采用 知识共享署名4.0 国际许可协议进行许可
原文链接:https://hongcyu.cn/posts/python-turtle.html
最后更新于:2020-12-03 16:34:04

Coffee