多进程数据共享

在上一篇博客中写了python 如何实现多进程同步操作, 在我用opencv 画图的时候发现了如果单纯的使用多进程不能实现数据共享, 后来在查阅相关文章后得到了解决, 完整代码在结尾

本人思路:

在学习过opencv 后我学会了如何使用鼠标作为画笔, 来绘画, 以及如何使用轨迹栏来动态修改数据, 于是我想把两者结合, 由于传统写的python 代码是流水线式的, 画笔的颜色设定之后只能通过修改参数来调整颜色

后来才想用多进程来解决这个问题, 在学会了多进程创建之后, 又发现进程之间的数据, 默认是无法共享的, 所以要解决数据共享的问题

大体的思路是这样的

opencv 并行加速 parallel_for_ opencv 多进程_数据

首先创建一个类

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)

这个类初始化的时候需要保存几个重要的信息:

  1. 画布创建, 以及设置他的背景颜色self.draw_bgc = np.zeros((280, 280, 3), np.uint8)
  2. 在调色的时候要显示颜色所以要创建一张背景图片来根据rgb 的值显示
  3. 在调色的时候显示背景颜色, 所以要存储不断变化的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)

opencv 并行加速 parallel_for_ opencv 多进程_数据_02

显示轨迹栏函数

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()

结果展示

opencv 并行加速 parallel_for_ opencv 多进程_ci_03

完整代码

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()