在wxpython中正确显示numpy数组cv2图像
Display numpy array cv2 image in wxpython correctly
我正在尝试将 numpy 数组(cv2 图像)转换为 wxpython 位图并正确显示。我研究了 SO 和其他地方的各种解决方案,但没有成功。您可以在下面的代码中看到我的两次尝试。
import wx
import cv2
import numpy as np
def create_wx_bitmap(cv2_image):
# type: (np.ndarray) -> wx.Bitmap
# My Attempt based on
height, width = cv2_image.shape[:2]
array = cv2_image # the OpenCV image
image = wx.Image(width, height)
image.SetData(array.tobytes())
wxBitmap = image.ConvertToBitmap()
return wxBitmap
# My other attempt:
# height, width = cv2_image.shape[:2]
# cv2_image_rgb = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB)
# return wx.Bitmap.FromBuffer(width, height, cv2_image_rgb)
class MyFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title)
cv2_image = cv2.imread("test1.png", cv2.IMREAD_ANYDEPTH | cv2.IMREAD_COLOR) # type: np.ndarray
print(cv2_image.dtype)
bitmap = create_wx_bitmap(cv2_image) # type: wx.Bitmap
wx.StaticBitmap(self, -1, bitmap, (0, 0), self.GetClientSize())
self.SetSize(bitmap.GetSize())
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame(None, "wxPython with OpenCV")
frame.Show()
app.MainLoop()
上面的代码似乎适用于 16 位(24 位深度)以下的图像。但是,位深度为 64 的图像会产生如下图所示的条带。(这是从 Blender 3D 以 16 位深度设置导出的渲染图):
我也尝试过转换数组数据类型,但似乎没有任何区别。
编辑(最终解决方案):
我的问题的解决方案是在 规范化数据 之后将数组转换为 np.uint8
,如 中所述。感谢@PetrBlahos 在他的回答中提到数据需要是 8 位 RGB。
def create_wx_bitmap(cv2_image):
# type: (np.ndarray) -> wx.Bitmap
height, width = cv2_image.shape[:2]
info = np.iinfo(cv2_image.dtype) # Get the information of the incoming image type
data = cv2_image.astype(np.float64) / info.max # normalize the data to 0 - 1
data = 255 * data # Now scale by 255
cv2_image = data.astype(np.uint8)
cv2_image_rgb = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB)
return wx.Bitmap.FromBuffer(width, height, cv2_image_rgb)
我用
dc.DrawBitmap(wx.Bitmap.FromBuffer(iw, ih, cv_image), 0, 0)
但 cv_image 必须是 rgb 值的 numpy 字节数组。因此,无论您做什么,都必须将数据转换为 8 位 RGB(或者可能是 RGBA,使用 FromBufferRGBA)。
我不太明白你的数据是如何构建的。 64 位意味着你有 4 个通道 (RGBA) 每个通道都是 16b 整数?
我想你可以使用 cv2.convertScaleAbs,或者 convertTo。
我正在尝试将 numpy 数组(cv2 图像)转换为 wxpython 位图并正确显示。我研究了 SO 和其他地方的各种解决方案,但没有成功。您可以在下面的代码中看到我的两次尝试。
import wx
import cv2
import numpy as np
def create_wx_bitmap(cv2_image):
# type: (np.ndarray) -> wx.Bitmap
# My Attempt based on
height, width = cv2_image.shape[:2]
array = cv2_image # the OpenCV image
image = wx.Image(width, height)
image.SetData(array.tobytes())
wxBitmap = image.ConvertToBitmap()
return wxBitmap
# My other attempt:
# height, width = cv2_image.shape[:2]
# cv2_image_rgb = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB)
# return wx.Bitmap.FromBuffer(width, height, cv2_image_rgb)
class MyFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title)
cv2_image = cv2.imread("test1.png", cv2.IMREAD_ANYDEPTH | cv2.IMREAD_COLOR) # type: np.ndarray
print(cv2_image.dtype)
bitmap = create_wx_bitmap(cv2_image) # type: wx.Bitmap
wx.StaticBitmap(self, -1, bitmap, (0, 0), self.GetClientSize())
self.SetSize(bitmap.GetSize())
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame(None, "wxPython with OpenCV")
frame.Show()
app.MainLoop()
上面的代码似乎适用于 16 位(24 位深度)以下的图像。但是,位深度为 64 的图像会产生如下图所示的条带。(这是从 Blender 3D 以 16 位深度设置导出的渲染图):
我也尝试过转换数组数据类型,但似乎没有任何区别。
编辑(最终解决方案):
我的问题的解决方案是在 规范化数据 之后将数组转换为 np.uint8
,如
def create_wx_bitmap(cv2_image):
# type: (np.ndarray) -> wx.Bitmap
height, width = cv2_image.shape[:2]
info = np.iinfo(cv2_image.dtype) # Get the information of the incoming image type
data = cv2_image.astype(np.float64) / info.max # normalize the data to 0 - 1
data = 255 * data # Now scale by 255
cv2_image = data.astype(np.uint8)
cv2_image_rgb = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2RGB)
return wx.Bitmap.FromBuffer(width, height, cv2_image_rgb)
我用
dc.DrawBitmap(wx.Bitmap.FromBuffer(iw, ih, cv_image), 0, 0)
但 cv_image 必须是 rgb 值的 numpy 字节数组。因此,无论您做什么,都必须将数据转换为 8 位 RGB(或者可能是 RGBA,使用 FromBufferRGBA)。 我不太明白你的数据是如何构建的。 64 位意味着你有 4 个通道 (RGBA) 每个通道都是 16b 整数?
我想你可以使用 cv2.convertScaleAbs,或者 convertTo。