2013-03-28 2 views
3

Я работаю над сенсорным Python-приложением, основанным на графическом интерфейсе PyQt4. Датчик генерирует 16-битные измерения ... 256 16-разрядных «пикселей» на «линию». Квадратное «изображение» получается путем получения 256 строк, в результате чего получается массив (256 256) Numpy из 16-разрядных чисел. Я просто хочу отобразить это как изображение в оттенках серого. Контур датчика работает в QThread и испускает сигнал QImage. Сигнал подключается к слоту, который отображает данные в главном графическом интерфейсе, упаковывая его в 32-разрядное изображение RGB. Конечно, чтобы упаковать 16-битные оттенки серого в 32-битное RGB-изображение, я вынужден масштабировать 16-битные пиксели до 8-бит, и значительное количество динамического диапазона теряется. Предоставляется MWE, которая показывает мою текущую стратегию (это, очевидно, не мое приложение с большим количеством резьбовых датчиков ... оно просто извлекает существенные части). Обратите внимание, что я новичок Python, и я делаю все возможное, чтобы не отставать от ...Преобразование 16-битных оттенков серого в QImage

#!/usr/bin/python 
# -*- coding: utf-8 -*- 

""" 
Grayscale to RGB32 QPixmap tests 
""" 

import sys 
import numpy as np 
from PyQt4 import QtGui, QtCore 

class PixmapTest(QtGui.QWidget): 

    def __init__(self): 
     super(PixmapTest, self).__init__() 
     self.initUI() 

    def initUI(self):  
     imglayout = QtGui.QHBoxLayout(self) 

     img_16bit = np.random.randint(0,65535,size=(256,256)).astype(np.uint32) 
     img_16bit_to_8bit = (img_16bit/65535.0 * 255).astype(np.uint32) 
     packed_img_array = (255 << 24 | (img_16bit_to_8bit) << 16 | (img_16bit_to_8bit) << 8 | (img_16bit_to_8bit)).flatten() 
     img = QtGui.QImage(packed_img_array, 256, 256, QtGui.QImage.Format_RGB32) 
     pixmap = QtGui.QPixmap(img.scaledToWidth(img.width()*2)) 

     imglabel = QtGui.QLabel(self) 
     imglabel.setPixmap(pixmap) 

     imglayout.addWidget(imglabel) 
     self.setLayout(imglayout) 

     self.move(300, 200) 
     self.setWindowTitle('QPixmap Test') 
     self.show()   

def main(): 

    app = QtGui.QApplication(sys.argv) 
    form = PixmapTest() 
    sys.exit(app.exec_()) 


if __name__ == '__main__': 
    main() 

В частности, мои вопросы:

  1. Есть ли лучший способ? Решение должно оставаться «легким» (т. Е. PyQt4 QImage/QPixmap). Я не могу использовать Matplotlib или что-нибудь тяжелое, поскольку он слишком медленный. Чем ближе к родному Python/Numpy, тем лучше. Я понимаю, что это, в конечном счете, ограничение класса QImage, но я надеялся, что есть умное решение, которое я просто не вижу, что позволяет мне поддерживать текущий сигнал/слот «проводки», который у меня есть.

  2. В результате экспериментов я обнаружил, что мне нужно объявить все массивы, которые в конечном итоге будут обработаны, чтобы закончить QImage как np.uint32 (хотя, похоже, работает и np.int32). Это не работает, если я просто объявляю предпоследний массив как uint32/int32. Я не понимаю, почему.

  3. Я играл с изменяющейся яркостью с Y' = 0.2126 * R + 0.7152 * G + 0.0722 * B и другими аналогичными преобразованиями. Вероятно, «полировка турки» здесь, но я думал, что включу это, потому что другие ответы на SX, похоже, указывают на то, что это важно. Несмотря на потерю динамического диапазона, кажется, что просто назначить одно и то же значение R, G, B, как в моем MWE.

В соответствии с просьбой в комментариях ниже, здесь гистограмма некоторых выборочных данных от датчика, чтобы проиллюстрировать динамический диапазон:

histogram of actual sensor data

+0

Можете ли вы показать гистограмму данных с датчика? Возможно, он не использует весь диапазон 16 бит. Например, вы можете сделать максимальное значение «белым» на «img_16bit/(img_16bit.max()/255.0)». Вы также можете найти максимальное и минимальное значение данных датчика и сопоставить их с 255 и 0. – HYRY

+0

@HYRY, добавлена ​​гистограмма, показывающая, что я использую полный диапазон 16-бит ... – ph0t0n

+0

Итак, большая часть данных находится в диапазоне 25000 - 45000, возможно, скопируйте данные в этот диапазон и сопоставьте их с 0 - 255. получить лучший результат. – HYRY

ответ

2

Здесь я использую некоторые данные функции для демонстрации:

y, x = np.mgrid[-10:10:256j, -10:10:256j] 
data = ((np.sin(y**2 + x**2) + 2) * 1000).astype(np.uint16) 

img_8bit = (data/256.0).astype(np.uint8) # use the high 8bit 
img_8bit = ((data - data.min())/(data.ptp()/255.0)).astype(np.uint8) # map the data range to 0 - 255 
img = QtGui.QImage(img_8bit.repeat(4), 256, 256, QtGui.QImage.Format_RGB32) 

При использовании высокого 8bit, это выглядит следующим образом:

enter image description here

Когда карта мин & максимального значения (0, 255), он выглядит следующим образом:

enter image description here

Для преобразования 8bit изображения в 32-х, вы можете просто позвонить img_8bit.repeat(4), это будет повторяться каждый байта 4 раза, поэтому память можно рассматривать как буфер uint32. Поскольку вы создаете QImage по Format_RGB32, а не Format_ARGB32, самый старший байт не используется.

Смежные вопросы