教你在python中用不同的方式画不同颜色的画布

作者:ywsydwsbn
博客主页:https://blog.csdn.net/ywsydwsbn
公众号:「做一个柔情的程序猿」
时间:2020-10-06 20:57
字数:7889
简介:先点赞在看,养成习惯!!!

文章目录

摘要

在这篇文章中将给大家讲解如何分别用numpy的方法,与numpy与cv2结合的方法创建空白画布,创建白色画布,与创建彩色画布。在讲解过程中还会介绍cv2进行通道分割cv2.split与通道合并cv2.merge的两个函数的具体使用以及深究numpy的ndarray数据结构的索引与赋值。

numpy的ndarray数据结构的索引与赋值

在使用画图工具的时候, 第一件事情就是创建一个新的空白画布,我们可以指定画布的大小和颜色。

那我们如何使用opencv来创建一个空白的画布(值相同的图片) ?

其实image的数据结构上的图片,本质上就是numpy里面的ndarray的对象,创建一个画布本质上就是创建一个同等规格的ndarray

创建一个新的特定尺寸的ndarray我们可以使用np.zeors 函数,我们将图像的高度(height),图像的宽度(width),以及图像的通道数channeltuple 类型传入np.zeros再次声明是tuple类型

另外由于不是所有的numpy类型的数值,都可以放到opencv中进行图像处理.

数值取值范围在0-255, 我们需要指定数据类型为uint8 unsigned integer 8-bit

np.zeros((height, width, channels), dtype="uint8")

举个例子:想创建一个800 x 600 x 3 的图片,一个BGR格式的图像,我们就得这么写:

# 初始化一个空画布 300×300 三通道 背景色为黑色 
canvas_black = np.zeros((600, 800, 3), dtype="uint8")

得到的效果如下:


黑色画布

注意: height写在前面
为什么Height写在前面?
就得知道opencv图像的数据结构是numpy,Image的属性,其实就是numpy的ndarray数据格式的属性。

我们可以直接获取img对象的诸多属性,例如我们打印lena图的属性,具体如下:

lena.jpg
 # -*- coding: utf-8 -*- 
import numpy as np
import cv2

# 导入一张图像 模式为彩色图片
img = cv2.imread('lena.jpg', cv2.IMREAD_COLOR)

print("================打印图像的属性================")
print("图像对象的类型 {}".format(type(img)))
print(img.shape)
print("图像宽度: {} pixels".format(img.shape[1]))
print("图像高度: {} pixels".format(img.shape[0]))
print("通道: {}".format(img.shape[2]))
print("图像分辨率: {}".format(img.size))
print("数据类型: {}".format(img.dtype))

输出结果

================打印图像的属性================
图像对象的类型 <class 'numpy.ndarray'>
(256, 256, 3)
图像宽度: 256 pixels
图像高度: 256 pixels
通道: 3
图像分辨率: 196608
数据类型: uint8

有时候我们也可以偷懒,如果我们想创建与另外一个图像尺寸相同的画布的时候,我们可以使用np.zeros_like

canvas_black = np.zeros_like(img)

创建空白画布

创建空白画布的函数如下:

def InitCanvas(width, height, color=(255, 255, 255)):
    canvas = np.ones((height, width, 3), dtype="uint8")
    canvas[:] = color
    return canvas

调用的时候传入图像的宽度、高度和画布的颜色。例如创建一个800*600 颜色为纯黑色的画布:

canvas = InitCanvas(800, 600, color=(255,255,255))

创建空白画布的完整代码如下:

'''
初始化画布
'''
import cv2
import numpy as np

def init_canvas(width, height, color=(255, 255, 255)):
    canvas = np.ones((height, width, 3), dtype="uint8")
    canvas[:] = color
    return canvas

canvas = init_canvas(200, 200, color=(125, 40, 255))

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

cv2.destroyAllWindows()

效果展示:

彩色画布

初始化白色的画布

白色的画布, 因为比较简单,而且三个通道的值都相同。

ps: 其实灰色的图片(GRAY2BGR),三个通道的值都相同。

那么我们创建一个全都是1的矩阵,然后乘上某个数值,问题是不是就解决了。

我们需要用到np.ones 函数

# 初始化一个空画布 300×300 三通道 背景色为白色 
canvas_white = np.ones((300, 300, 3), dtype="uint8")

接下来, 需要乘上一个整数,255 (你可以填入0-255的任意值)

canvas_white *= 255

这种运算称之为 全局乘法

具体代码如下:

import cv2
import numpy as np
canvas_white = np.ones((300, 300, 3), dtype="uint8")
canvas_white *= 255
cv2.imshow('canvas', canvas_white)
cv2.waitKey(0)
cv2.destroyAllWindows()

创建的白色画布如下

白色画布

初始化彩色的画布

利用cv2的内置方法merge与split

我们初始化BGR的图片canvas_white 之后将原来的图片进行通道分离,之后分别乘上BGR三个通道的整数值,然后将三个通道合并在一起,就得到我们想要的彩图纯色背景。

那通道的分离我们需要用到的函数是cv2.split(img).

# 将原来的三个通道抽离出来, 分别乘上各个通道的值
(channel_b, channel_g, channel_r) = cv2.split(canvas)

channel_b 蓝色通道channel_g 绿色通道channel_r 红色通道,都是二维的ndarray对象。

我们指定一种颜色,例如 color = (100, 20, 50))

注意:我们这里的颜色指的BGR格式

也就是

B -> 100
G -> 20
R -> 50

接下来我们分别将其乘上对应的值.

# 颜色的值与个通道的全1矩阵相乘
channel_b *= color[0]
channel_g *= color[1]
channel_r *= color[2]

接下来我们将三个通道重新合并,需要用到的函数是cv2.merge

cv2.merge([channel_b, channel_g, channel_r])

注意:三个通道的矩阵以list [] 的方式传入merge函数.

综合起来,就是我们的第一个初始化彩色背景的函数

# 初始化一个彩色的画布 - cv2版本
def init_canvas(width, height, color=(255, 255, 255)):
    canvas = np.ones((height, width, 3), dtype="uint8")

    # 将原来的三个通道抽离出来, 分别乘上各个通道的值
    (channel_b, channel_g, channel_r) = cv2.split(canvas)
    # 颜色的值与个通道的全1矩阵相乘
    channel_b *= color[0]
    channel_g *= color[1]
    channel_r *= color[2]

    # cv.merge 合并三个通道的值
    return cv2.merge([channel_b, channel_g, channel_r])

具体实现代码如下:

'''
初始化画布
'''
import cv2
import numpy as np

# 初始化一个彩色的画布 - cv2版本
def init_canvas(width, height, color=(255, 255, 255)):
    canvas = np.ones((height, width, 3), dtype="uint8")

    # 将原来的三个通道抽离出来, 分别乘上各个通道的值
    (channel_b, channel_g, channel_r) = cv2.split(canvas)
    # 颜色的值与个通道的全1矩阵相乘
    channel_b *= color[0]
    channel_g *= color[1]
    channel_r *= color[2]

    # cv.merge 合并三个通道的值
    return cv2.merge([channel_b, channel_g, channel_r])

canvas = init_canvas(200, 200, color=(125, 100, 255))

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

cv2.destroyAllWindows()

运行效果:

image.png

注意:此函数使用 cv2.split 非常耗时 所以只有在需要的时候才能做到。 否则用Numpy索引。

利用numpy内置的索引

使用numpy原生的方法, 性能会比opencv中的要好。我们直接使用numpy的ndarray的索引的方法。

例如 canvas[:,:,0] 选中的是所有行,所有列,像素元素的第一个值,也就是,所有B通道的值。

然后对其进行赋值:

canvas[:,:,0] = color[0]

完整版本的函数如下,B/G/R通道分别进行赋值:

def init_canvas(width, height, color=(255, 255, 255)):
    canvas = np.ones((height, width, 3), dtype="uint8")
    # Blue 
    canvas[:,:,0] = color[0]
    # Green
    canvas[:,:,1] = color[1]
    # Red
    canvas[:,:,2] = color[2]

    return canvas

具体实现代码如下:

'''
初始化画布
'''
import cv2
import numpy as np

def init_canvas(width, height, color=(255, 255, 255)):
    canvas = np.ones((height, width, 3), dtype="uint8")
    # Blue 
    canvas[:,:,0] = color[0]
    # Green
    canvas[:,:,1] = color[1]
    # Red
    canvas[:,:,2] = color[2]

    return canvas

canvas = init_canvas(200, 200, color=(125, 100, 255))

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

cv2.destroyAllWindows()

运行实现的效果和第一种方法一样:

image.png

实际上我们还有更快的方法, 可以实现这个功能, 这就需要你熟练掌握Numpy的使用技巧.

我们可以直接赋值color

canvas[:] = color

完整实现过程如下:

'''
初始化画布
'''
import cv2
import numpy as np

def init_canvas(width, height, color=(255, 255, 255)):
    canvas = np.ones((height, width, 3), dtype="uint8")
    canvas[:] = color
    return canvas

canvas = init_canvas(200, 200, color=(125, 40, 255))

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

cv2.destroyAllWindows()

运行的效果:

image.png

综合实验-初始化背景

在这个综合实验里会分别用上述的方法,创建黑色背景,白色背景,彩色背景。

具体代码如下:

'''
初始化一个空白的画布
并指定画布的颜色
'''

import cv2
import numpy as np

# 初始化一个空画布 300×300 三通道 背景色为黑色 
canvas_black = np.zeros((300, 300, 3), dtype="uint8")
cv2.imshow("canvas_black", canvas_black)

# 初始化一个空画布 300×300 三通道 背景色为白色 
canvas_white = np.ones((300, 300, 3), dtype="uint8")
canvas_white *= 255

cv2.imshow("canvas_white", canvas_white)

'''
初始化一个彩色的画布 - cv2版本
此函数使用 cv2.split 非常耗时 所以只有在需要的时候才能做到。 否则用Numpy索引。

'''
def InitCanvasV1(width, height, color=(255, 255, 255)):
    canvas = np.ones((height, width, 3), dtype="uint8")

    # 将原来的三个通道抽离出来, 分别乘上各个通道的值
    (channel_b, channel_g, channel_r) = cv2.split(canvas)
    # 颜色的值与个通道的全1矩阵相乘
    channel_b *= color[0]
    channel_g *= color[1]
    channel_r *= color[2]

    # cv.merge 合并三个通道的值
    return cv2.merge([channel_b, channel_g, channel_r])

'''
初始化一个彩色的画布 - numpy版本
使用numpy的索引 赋值
'''
def InitCanvasV2(width, height, color=(255, 255, 255)):
    canvas = np.ones((height, width, 3), dtype="uint8")
    # Blue 
    canvas[:,:,0] = color[0]
    # Green
    canvas[:,:,1] = color[1]
    # Red
    canvas[:,:,2] = color[2]

    return canvas

'''
初始化终极版本

熟练掌握 numpy 才可以提高工作效率哦
'''
def InitCanvasV3(width, height, color=(255, 255, 255)):
    canvas = np.ones((height, width, 3), dtype="uint8")
    canvas[:] = color
    return canvas

# 初始化一个彩色的画布
canvas_color = InitCanvasV2(300, 300, color=(100, 20, 50))
cv2.imshow("canvas_color", canvas_color)

# 等待e键按下 关闭所有窗口
while cv2.waitKey(0) != ord('e'):
    continue
cv2.destroyAllWindows()

运行结果:

在这里插入图片描述

资源传送门

  • 关注【做一个柔情的程序猿】公众号
  • 在【做一个柔情的程序猿】公众号后台回复 【python资料】【2020秋招】 即可获取相应的惊喜哦!

「❤️ 感谢大家」

  1. 点赞支持下吧,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)
  2. 欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343