多进程数据共享
在上一篇博客中写了python 如何实现多进程同步操作, 在我用opencv 画图的时候发现了如果单纯的使用多进程不能实现数据共享, 后来在查阅相关文章后得到了解决, 完整代码在结尾
本人思路:
在学习过opencv 后我学会了如何使用鼠标作为画笔, 来绘画, 以及如何使用轨迹栏来动态修改数据, 于是我想把两者结合, 由于传统写的python 代码是流水线式的, 画笔的颜色设定之后只能通过修改参数来调整颜色
后来才想用多进程来解决这个问题, 在学会了多进程创建之后, 又发现进程之间的数据, 默认是无法共享的, 所以要解决数据共享的问题
大体的思路是这样的
首先创建一个类
1. 创建一个类, 并将想要共享的数据存储在这个类的初始化操作中, 在后期就可以用这个对象的属性来保存这个数据
```python
class cv_draw():
# 设置函数的目的是为了返回给self 的值当做globol 数据来记录返回值
def __init__(self):
self.draw_bgc = np.zeros((280, 280, 3), np.uint8)
self.color_bgc = np.zeros((280, 280, 3), np.uint8)
self.r = Value('i', 255)
self.g = Value('i', 255)
self.b = Value('i', 255)
这个类初始化的时候需要保存几个重要的信息:
- 画布创建, 以及设置他的背景颜色
self.draw_bgc = np.zeros((280, 280, 3), np.uint8)
- 在调色的时候要显示颜色所以要创建一张背景图片来根据rgb 的值显示
- 在调色的时候显示背景颜色, 所以要存储不断变化的r,g,b 的值
在创建self.rgb 的变量的时候要注意调用Value 函数来将其设置为共享的数据, 这样在多进程调用的时候才能够动态的修改数据但是在使用Value() 之后如果想要获取其值的话就需要用self.r.value方法来获取
self.r中的数据
关于Value函数的参数'i'
表示int 数据类型, 255
表示初始化的值
self.r = Value('i', 255)
self.g = Value('i', 255)
self.b = Value('i', 255)
显示轨迹栏函数
def show_color(self):
name = 'color_bar'
cv.namedWindow(name)
cv.createTrackbar('R', name, 0, 255, self.nothing)
cv.createTrackbar('G', name, 0, 255, self.nothing)
cv.createTrackbar('B', name, 0, 255, self.nothing)
while True:
k = cv.waitKey(1) & 0xff
if k == 27:
break
cv.imshow('color_bar', self.color_bgc)
self.r.value = cv.getTrackbarPos('R', 'color_bar')
self.g.value = cv.getTrackbarPos('G', 'color_bar')
self.b.value = cv.getTrackbarPos('B', 'color_bar')
self.color_bgc[:] = [self.b.value, self.g.value, self.r.value]
定义画图函数
在这里展示的是画一个圆(鼠标双击)cv.circle(self.draw_bgc, (x, y), 100, (self.b.value, self.g.value, self.r.value), -1)
第四个参数表示的是画图的颜色, 使用共享的数据
def draw_circle(self, event, x, y, flags, param):
if event == cv.EVENT_LBUTTONDBLCLK:
cv.circle(self.draw_bgc, (x, y), 100, (self.b.value, self.g.value, self.r.value), -1)
def draw(self):
cv.namedWindow('image')
cv.setMouseCallback('image', self.draw_circle)
while True:
cv.imshow('image', self.draw_bgc)
if cv.waitKey(20) & 0xff == 27:
break
cv.destroyAllWindows()
主函数
调用多进程的方法来实现我想要的功能,注意这里不能使用多线程, 我尝试过使用多线程但是会出错, 不知道为啥, 最后用多进程的时候就不会报错
if __name__ == '__main__':
paint = cv_draw()
bar = Process(target=paint.show_color)
draw = Process(target=paint.draw)
bar.start()
draw.start()
结果展示
完整代码
import cv2 as cv
import numpy as np
import threading
from multiprocessing import Process, Pipe, Pool, Value
# 建立鼠标回调函数
import time
class cv_draw():
# 设置函数的目的是为了返回给self 的值当做globol 数据来记录返回值
def __init__(self):
self.draw_bgc = np.zeros((280, 280, 3), np.uint8)
self.color_bgc = np.zeros((280, 280, 3), np.uint8)
self.r = Value('i', 255)
self.g = Value('i', 255)
self.b = Value('i', 255)
def nothing(self):
pass
def show_color(self):
name = 'color_bar'
cv.namedWindow(name)
cv.createTrackbar('R', name, 0, 255, self.nothing)
cv.createTrackbar('G', name, 0, 255, self.nothing)
cv.createTrackbar('B', name, 0, 255, self.nothing)
while True:
k = cv.waitKey(1) & 0xff
if k == 27:
break
cv.imshow('color_bar', self.color_bgc)
self.r.value = cv.getTrackbarPos('R', 'color_bar')
self.g.value = cv.getTrackbarPos('G', 'color_bar')
self.b.value = cv.getTrackbarPos('B', 'color_bar')
self.color_bgc[:] = [self.b.value, self.g.value, self.r.value]
def draw_circle(self, event, x, y, flags, param):
if event == cv.EVENT_LBUTTONDBLCLK:
cv.circle(self.draw_bgc, (x, y), 100, (self.b.value, self.g.value, self.r.value), -1)
def draw(self):
cv.namedWindow('image')
cv.setMouseCallback('image', self.draw_circle)
while True:
cv.imshow('image', self.draw_bgc)
if cv.waitKey(20) & 0xff == 27:
break
cv.destroyAllWindows()
if __name__ == '__main__':
paint = cv_draw()
bar = Process(target=paint.show_color)
draw = Process(target=paint.draw)
bar.start()
draw.start()