【震驚】手把手教你用python做繪圖工具(一)

在這篇博客里將為你介紹如何通過numpy和cv2進行結和去創建畫布,包括空白畫布、白色畫布和彩色畫布。創建畫布是製作繪圖工具的前提,有了畫布我們就可以在畫布上盡情的揮灑自己的藝術細胞。

還在為如何去繪圖煩惱的小夥伴趕緊看過來,這裡手把手教你解決問題~~~~

當然還是講究一下規則:先點贊再看,尊重一下作者。年輕人還是要講點武德的。。。

廢話不多說,進入正題→→→

1.創建空白畫布

定義一個函數傳入圖像的寬度、高度和畫布的顏色,空白畫布顏色傳入的RGB值為(255,255,255),具體函數如下:

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

例如:在這個空白的畫布上創建500*500顏色為純黑色的畫布,可表示為:

canvas = InitCanvas(500, 500, color=(0,0,0))

實現完整代碼如下:


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

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

canvas = InitCanvas(500, 500, color=(0, 0, 0))
cv2.imshow('canvas', canvas)
cv2.waitKey(0)
cv2.destroyAllWindows()

可能有些人不能理解話不要創建原理,下面進行講解:
1、創建一個畫布本質上就是創建一個同等規格的 numpy 的 ndarray 對象;
2、創建一個新的特定尺寸的 ndarray 可以使用 np.zeors 函數, 我們將圖像的高度(height), 圖像的寬度(width)以及圖像的通道數channel 以tuple 類型傳入np.zeros 。 再次聲明是tuple類型
3、另外由於不是所有的numpy類型的數值都可以放到opencv中進行圖像處理,所以數值取值範圍在0-255, 需要指定數據類型為uint8 unsigned integer 8-bit
具體實現:
np.zeros((height, width, channels), dtype="uint8")

2.初始化白色的畫布

方法一

在創建的空白畫布的顏色修改為(255,255,255),即可得到白色的畫布,具體代碼如下:


import cv2
import numpy as np

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

canvas = InitCanvas(500, 500, color=(255, 255, 255))
cv2.imshow('canvas', canvas)
cv2.waitKey(0)
cv2.destroyAllWindows()

方法二

首先想到的是白色,又因為比較簡單,三個通道的值都相同。

ps: 其實灰色的圖片(GRAY2BGR), 三個通道的值都相同.

那麼我們創建一個全都是1的矩陣,然後,乘上某個數值,問題是不是就解決了。

我們需要用到np.ones 函數

# 初始化一個空畫布 500×500 三通道 背景色為白色 
canvas = np.ones((500, 500, 3), dtype="uint8")

接下來, 需要乘上一個整數255 (你可以填入0-255的任意值)

canvas_white *= 255

完整實現代碼如下,結果和方法一一樣:

import cv2
import numpy as np

canvas = np.ones((500, 500, 3), dtype="uint8")
canvas *= 255

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

3. 初始化彩色的畫布

3.1 利用cv2的內置方法merge與split

我們初始化BGR的圖片canvas之後將原來的圖片進行通道分離,分別乘上BGR三個通道的整數值,然後將三個通道合併在一起,就得到我們想要的彩圖純色背景。

那通道的分離需要用到的函數是cv2.split(img),具體用法如下:

# 將原來的三個通道抽離出來, 分別乘上各個通道的值
(channel_b, channel_g, channel_r) = cv2.split(canvas)
  • channel_b 藍色通道
  • channel_g 綠色通道
  • channel_r 紅色通道
  • 都是二維的ndarray對象

我們指定一種顏色, 例如 color = (140, 30, 60))

注意, 我們這裡的顏色指的BGR格式

也就是

  • B -> 140
  • G -> 30
  • R -> 60

接下來分別將其乘上對應的值

# 顏色的值與個通道的全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函數.

綜合以上初始化彩色背景的函數可表示為:

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

# 初始化一個彩色的畫布 - cv2版本
def InitCanvas(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 = InitCanvas(500, 500, color=(140, 30,60))
cv2.imshow('canvas', canvas)
cv2.waitKey(0)
cv2.destroyAllWindows()

canvas = InitCanvas(500, 500, color=(140, 30,60)) 裏面的color可以自己自定義0-255之間的值。

3.2 利用numpy內置的索引

以上的方法創建起來非常的耗時,對於追求完美的小夥伴們可能不會去使用這種方法。那麼來了,還有另外一種方法:

使用numpy原生的方法性能會比opencv中的要好。

可以直接使用numpy的ndarray的索引的方法。

例如 : canvas[:,:,0] 選中的是所有行和所有列像素元素的第一個值,也就是, 所有B通道的值. 然後對其進行賦值:

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

具體使用如圖:

完整使用的代碼如下:

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

def InitCanvas(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 = InitCanvas(500, 500, color=(125, 50, 255))

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

cv2.destroyAllWindows()

4. 綜合實驗-初始化背景

在這個綜合實驗里會創建黑色背景、白色背景、彩色背景。

'''
初始化一個空白的畫布
並指定畫布的顏色
'''
import cv2
import numpy as np

# 初始化一個空畫布 500×500 三通道 背景色為黑色 
canvas_black = np.zeros((500, 500, 3), dtype="uint8")
cv2.imshow("canvas_black", canvas_black)

# 初始化一個空畫布 500×500 三通道 背景色為白色 
canvas_white = np.ones((500, 500, 3), dtype="uint8")
canvas_white *= 255

cv2.imshow("canvas_white", canvas_white)

'''
初始化一個彩色的畫布 - cv2版本
'''
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

'''
初始化終極版本
'''
def InitCanvasV3(width, height, color=(255, 255, 255)):
    canvas = np.ones((height, width, 3), dtype="uint8")
    canvas[:] = color
    return canvas

# 初始化一個彩色的畫布
canvas_color = InitCanvasV2(500, 500, color=(100, 20, 50))
cv2.imshow("canvas_color", canvas_color)

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

資源傳送門

  • 關注【做一個柔情的程序猿】公眾號
  • 在【做一個柔情的程序猿】公眾號後台回復 【python資料】【2020秋招】 即可獲取相應的驚喜哦!

「❤️ 感謝大家」

  • 點贊支持下吧,讓更多的人也能看到這篇內容(收藏不點贊,都是耍流氓 -_-)
  • 歡迎在留言區與我分享你的想法,也歡迎你在留言區記錄你的思考過程