C#通过共享内存传图像数据给python


C# 和Python通过共享内存块test1实现


C#

 private void button1_Click(object sender, EventArgs e)
 {
     try
     {
         Bitmap b = new Bitmap("test.bmp");
         MemoryStream ms = new MemoryStream();
         b.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
         byte[] bytes = ms.GetBuffer();  //byte[]   bytes=   ms.ToArray(); 
         ms.Close();

         var mmf = MemoryMappedFile.CreateOrOpen("test1", bytes.Length, MemoryMappedFileAccess.ReadWrite);
         var viewAccessor = mmf.CreateViewAccessor(0, bytes.Length);
         viewAccessor.Write(0, bytes.Length); ;
         viewAccessor.WriteArray<byte>(0, bytes, 0, bytes.Length);
         MessageBox.Show("write ok"+ bytes.Length.ToString());
     }
     catch (System.Exception s)
     {
         MessageBox.Show(s.Message);
     }
 }

在这里插入图片描述


Python

byteSize 通过上面的C#图像显示框得到

import mmap
import cv2
import numpy as np
byteSize = 1921078
file_name = 'test1'
import struct
import matplotlib.pyplot as plt
# python读取共享内存
f = mmap.mmap(0, byteSize, file_name, mmap.ACCESS_READ)
#print(f.read(byteSize))

f_type=str(f.read(2)) #这个就可以用来读取 文件类型 需要读取2个字节
file_size_byte=f.read(4)# 这个可以用来读取文件的大小 需要读取4个字节
f.seek(f.tell()+4) # 跳过中间无用的四个字节
file_ofset_byte=f.read(4) # 读取位图数据的偏移量
f.seek(f.tell()+4) # 跳过无用的两个字节
file_wide_byte=f.read(4) #读取宽度字节
file_height_byte=f.read(4) #读取高度字节
f.seek(f.tell()+2) ## 跳过中间无用的两个字节
file_bitcount_byte=f.read(4) #得到每个像素占位大小


#下面就是将读取的字节转换成指定的类型
f_size,=struct.unpack('l',file_size_byte)
f_ofset,=struct.unpack('l',file_ofset_byte)
f_wide,=struct.unpack('l',file_wide_byte)
f_height,=struct.unpack('l',file_height_byte)
f_bitcount,=struct.unpack('i',file_bitcount_byte)
print("类型:",f_type,"大小:",f_size,"位图数据偏移量:",f_ofset,"宽度:",f_wide,"高度:",f_height,"位图:",f_bitcount)


'然后来读取颜色表'
color_table=np.empty(shape=[256,4],dtype=int)
f.seek(54) #跳过文件信息头和位图信息头
for i in range(0,256):
    b=struct.unpack('B',f.read(1))[0];
    g = struct.unpack('B', f.read(1))[0];
    r = struct.unpack('B', f.read(1))[0];
    alpha = struct.unpack('B', f.read(1))[0];
    color_table[i][0]=r
    color_table[i][1]=g
    color_table[i][2]=b
    color_table[i][3]=255

'下面部分用来读取BMP位图数据区域,将数据存入numpy数组'
#首先对文件指针进行偏移
f.seek(f_ofset)
#因为图像是8位伪彩色图像,所以一个像素点占一个字节,即8位
img=np.empty(shape=[f_height,f_wide,4],dtype=int)
cout = 0
for y in range(0, f_height):
    for x in range(0,f_wide):
        cout=cout+1
        index=struct.unpack('B',f.read(1))[0]
        img[f_height-y-1,x]=color_table[index]
    while cout %4 !=0:
        f.read(1)
        cout=cout+1
plt.imshow(img)
plt.show()
f.close()


f.close()

在这里插入图片描述

但是python解析成图像数据太慢了,要2s多

import mmap
import cv2
import numpy as np
import datetime

starttime = datetime.datetime.now()

byteSize = 1921078
file_name = 'test1'
import struct
import matplotlib.pyplot as plt
# python读取共享内存
f = mmap.mmap(0, byteSize, file_name, mmap.ACCESS_READ)
#print(f.read(byteSize))

f_type=str(f.read(2)) #这个就可以用来读取 文件类型 需要读取2个字节
file_size_byte=f.read(4)# 这个可以用来读取文件的大小 需要读取4个字节
f.seek(f.tell()+4) # 跳过中间无用的四个字节
file_ofset_byte=f.read(4) # 读取位图数据的偏移量
f.seek(f.tell()+4) # 跳过无用的两个字节
file_wide_byte=f.read(4) #读取宽度字节
file_height_byte=f.read(4) #读取高度字节
f.seek(f.tell()+2) ## 跳过中间无用的两个字节
file_bitcount_byte=f.read(4) #得到每个像素占位大小


#下面就是将读取的字节转换成指定的类型
f_size,=struct.unpack('l',file_size_byte)
f_ofset,=struct.unpack('l',file_ofset_byte)
f_wide,=struct.unpack('l',file_wide_byte)
f_height,=struct.unpack('l',file_height_byte)
f_bitcount,=struct.unpack('i',file_bitcount_byte)
print("类型:",f_type,"大小:",f_size,"位图数据偏移量:",f_ofset,"宽度:",f_wide,"高度:",f_height,"位图:",f_bit+count)


'然后来读取颜色表'
color_table=np.empty(shape=[256,4],dtype=int)
f.seek(54) #跳过文件信息头和位图信息头
for i in range(0,256):
    b=struct.unpack('B',f.read(1))[0];
    g = struct.unpack('B', f.read(1))[0];
    r = struct.unpack('B', f.read(1))[0];
    alpha = struct.unpack('B', f.read(1))[0];
    color_table[i][0]=r
    color_table[i][1]=g
    color_table[i][2]=b
    color_table[i][3]=255

'下面部分用来读取BMP位图数据区域,将数据存入numpy数组'
#首先对文件指针进行偏移
f.seek(f_ofset)
#因为图像是8位伪彩色图像,所以一个像素点占一个字节,即8位
img=np.empty(shape=[f_height,f_wide,4],dtype=int)
cout = 0

starttime1 = datetime.datetime.now()

for y in range(0, f_height):
    for x in range(0,f_wide):
        cout=cout+1
        index=struct.unpack('B',f.read(1))[0]
        img[f_height-y-1,x]=color_table[index]
    while cout %4 !=0:
        f.read(1)
        cout=cout+1

endtime1 = datetime.datetime.now()

endtime = datetime.datetime.now()

print(endtime1 - starttime1)
print(endtime - starttime)

plt.imshow(img)
plt.show()
f.close()


f.close()

在这里插入图片描述

下一步改进,打算用opencv读取看看

可以,可以,Opencv万岁,只用了3.9ms

import mmap
import cv2
import numpy as np
import datetime

starttime = datetime.datetime.now()
byteSize = 1921078
file_name = 'test1'
f = mmap.mmap(0, byteSize, file_name, mmap.ACCESS_READ)
img = cv2.imdecode(np.frombuffer(f, np.uint8), cv2.IMREAD_COLOR)
endtime = datetime.datetime.now()
print(endtime-starttime)

在这里插入图片描述

补充:

# 1、使用cv2
import cv2
import numpy as np
from matplotlib import pyplot as plt
from PIL import Image
img_url = r'test.png'
with open(img_url, 'rb') as f:
    a = f.read()
 
# 二进制数据流转np.ndarray [np.uint8: 8位像素]
img = cv2.imdecode(np.frombuffer(a, np.uint8), cv2.IMREAD_COLOR)
# # 将bgr转为rbg
rgb_img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
print(rgb_img)
# np.ndarray转IMAGE
a = Image.fromarray(rgb_img)
print(a)
# 显示图片
a.show()
 
2、使用io.BytesIO
import io
from PIL import Image
img_url = r'C:\Users\xxc\Desktop\capture.png'
with open(img_url, 'rb') as f:
    a = f.read()
print(type(a))
# 将字节对象转为Byte字节流数据,供Image.open使用
byte_stream = io.BytesIO(a)  
print(type(byte_stream))
roiImg = Image.open(byte_stream)  
# 图片保存 
roiImg.save(r'C:\Users\xxc\Desktop\save.png')
 

cv2和io.BytesIO相比,多了一步bgr转rbg,可能使用io.BytesIO更加方便。


版权声明:本文为qq_41375318原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。