QPixmap.scaled显示小ROI区域图像意外变形问题求助
问题描述
我正在使用Python开发一款GUI程序,用于展示相机采集图像及处理后的图像。为此实现了ROI功能,用户可在承载图像的QLabel中选择特定区域,仅显示该区域内容。图像本身为numpy数组,转换代码如下:
self.spec = fft2d.dft2(image) trnsfImg = np.log(np.abs(self.spec) + 0.00000000001) # 防止除零(非最优方案) trnsfImg = trnsfImg[self.s_top:self.s_top+self.s_hei, self.s_left:self.s_left+self.s_wid] trnsfImg = (255*(trnsfImg-trnsfImg.min())/(trnsfImg.max()-trnsfImg.min())) trnsfImg = trnsfImg.astype(np.uint8) # QLabel要求数据类型为uint8 qimg = QImage(trnsfImg, trnsfImg.shape[1], trnsfImg.shape[0], QImage.Format_Indexed8) self.spec_pix = QtGui.QPixmap.fromImage(qimg).scaled(self._ui.specLB.width(), self._ui.specLB.height()) self._ui.specLB.setPixmap(self.spec_pix)
选择较大区域时显示正常,但选择小区域时图像出现意外变形;而用PIL保存转换前的numpy图像显示正常,PIL代码如下:
im = Image.fromarray(trnsfImg).convert('L') im.save("PathtoImage/img.jpeg")
原因分析
问题核心出在**QImage.Format_Indexed8的使用逻辑**上:
- 该格式要求QImage必须绑定一个颜色表,用来将像素的uint8索引值映射为实际的颜色。如果不手动设置,QImage会使用系统默认的颜色表,而这个默认表并非标准的灰度渐变表,当图像尺寸较小时,像素的灰度值会被错误映射,导致色块变形。
- PIL的
convert('L')会直接将uint8数值作为灰度值处理,不需要额外颜色表,因此保存的图像能正确显示灰度层次。 - 大尺寸图像的像素数量多,默认颜色表的误差会被视觉平均,所以问题不明显;小尺寸图像的像素少,每个像素的映射错误都会被放大,变形就会很突出。
解决方法
有两种可行的修复方案:
方案1:改用灰度专用格式(推荐)
如果你的PyQt版本在5.13及以上,可以直接将QImage格式替换为QImage.Format_Grayscale8,这是专门为8位灰度图像设计的格式,无需额外颜色表:
qimg = QImage(trnsfImg, trnsfImg.shape[1], trnsfImg.shape[0], QImage.Format_Grayscale8)
方案2:手动添加灰度颜色表
若使用旧版PyQt不支持Format_Grayscale8,可以手动创建256级灰度颜色表并绑定到QImage:
qimg = QImage(trnsfImg, trnsfImg.shape[1], trnsfImg.shape[0], QImage.Format_Indexed8) # 生成256级灰度的颜色表 gray_color_table = [QtGui.qRgb(i, i, i) for i in range(256)] qimg.setColorTable(gray_color_table)
内容的提问来源于stack exchange,提问作者xenon
相关产品推荐
相关产品推荐

