OpenCV保存PNG图像时颜色与imshow显示不一致且区域透明问题
问题原因
- mss库
grab方法返回的图像为带alpha通道的BGRA四通道格式,你直接转换为numpy数组后,调用cv2.circle、cv2.rectangle时传入的是三通道BGR颜色值,OpenCV会默认将绘制区域的alpha通道赋值为0(全透明)。PNG格式支持透明通道,保存后不同查看工具的背景色不同,就会出现VSCode中显黑、系统照片应用中显白的差异;而cv2.imshow默认忽略alpha通道,所以显示效果符合预期。 - 调用
cv2.circle时传入的颜色值(320, 159, 22)存在超范围问题:8位图像的单通道颜色取值范围为0-255,320会被自动截断为64,实际绘制颜色和你预期的不一致。 - 代码存在笔误:
centers.append((cY,cY))错误,应该存储(cX, cY)才能拿到正确的中心点坐标。
修复方案
优先选择去掉alpha通道的方案,不需要透明效果的话更稳定,修改后的代码如下:
import numpy as np import cv2 from skimage.metrics import structural_similarity import mss from time import sleep def find_diff(before, after): # mss返回的是BGRA四通道,先转为BGR三通道,移除alpha通道 before = np.array(before) before = cv2.cvtColor(before, cv2.COLOR_BGRA2BGR) after = np.array(after) after = cv2.cvtColor(after, cv2.COLOR_BGRA2BGR) # Convert images to grayscale before_gray = cv2.cvtColor(before, cv2.COLOR_BGR2GRAY) after_gray = cv2.cvtColor(after, cv2.COLOR_BGR2GRAY) # Compute SSIM between two images (score, diff) = structural_similarity(before_gray, after_gray, full=True) diff = (diff * 255).astype("uint8") # Threshold the difference image, followed by finding contours to # obtain the regions of the two input images that differ thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] contours = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours = contours[0] if len(contours) == 2 else contours[1] centers = [] for c in contours: area = cv2.contourArea(c) if area > 40: # Find centroid M = cv2.moments(c) cX = int(M["m10"] / M["m00"]) cY = int(M["m01"] / M["m00"]) # 修复坐标存储错误 centers.append((cX,cY)) # 修复颜色值超范围问题,BGR三个通道取值都控制在0-255之间 cv2.circle(after, (cX, cY), 2, (220, 159, 22), -1) #draw boxes on diffs x, y, w, h = cv2.boundingRect(c) cv2.rectangle(after, (x, y), (x + w, y + h), (36, 255, 12), 2) cv2.imwrite("debug.png", after) cv2.imshow('after', after) cv2.waitKey(0) cv2.destroyAllWindows() return centers before = mss.mss().grab((466, 325, 1461, 783)) sleep(3) after = mss.mss().grab((466, 325, 1461, 783)) relative_diffs = find_diff(before, after)
如果需要保留alpha通道,只需要将绘图的颜色值改为四通道,比如(36, 255, 12, 255),最后一位255代表完全不透明即可。
内容的提问来源于stack exchange,提问作者vincenthavinh
相关产品推荐
相关产品推荐

