PDA

View Full Version : grayscaled image from number matrix



mshemuni
3rd April 2013, 00:03
Hi everyone.
I have a problem with imaging.
I have a huge(40MB) 8 bit(0-255) text file. There is 3712 rows and 3712 columns. (Actually there is two files. One of them is image and the other one contant two numbers known as zscale coefficient)
This file is actually an image and I want to paint it.
I tried with qGraphicsView. As you understood there is 3712x3712 pixels so my script crashed.
How can I do that? Help me...
You can reach to scale and image files here (https://docs.google.com/file/d/0B6wVJYhgnHaiWFBJVzVaTVZ0bWM/edit?usp=sharing).

wysota
3rd April 2013, 00:14
As you understood there is 3712x3712 pixels so my script crashed.
It's not that much. If it crashes then it means your code is incorrect. Handling a 14Mpix image is not that big of a deal.

d_stranz
3rd April 2013, 17:09
Right, at a pixel depth of 8 bits (for greyscale), this works out to about 80 MB. Even at 32 bits, that's still only 320 MB which is well within even 32-bit OS limits. So, I also think there's a bug in the code.

Creating a greyscale image from 8-bit data is easy. The QImage should be a member variable of your QWidget class so you don't have to recalculate it for every paintEvent.



long index= 0;
QImage image( 3172, 3172, QImage::Format_RGB32 ); // should be a member variable of your widget class
for ( int i = 0; i < 3172; i++ )
{
for ( j = 0; j < 3172; j++ )
{
QRgb color = qRgb( data[ index ], data[ index ], data[ index ] );
image.setPixel( i, j, color );
index++;
}
}


In the paintEvent():



QPainter painter;
painter.drawImage( QPoint( 0, 0 ), image );

wysota
3rd April 2013, 17:52
At 8 bits it works out to 14MB as there is one byte per pixel ;)

d_stranz
4th April 2013, 00:37
Oh right, I was counting bits. Duh.

I did not see a format for either QPixmap or QImage that has 8 bits per pixel, only 1, 16, or 32 bits, unless I'm reading the docs incorrectly. So he'd still need about 50 MB for a 32-bit pixmap, which is certainly do-able.

wysota
4th April 2013, 07:00
Oh right, I was counting bits. Duh.

I did not see a format for either QPixmap or QImage that has 8 bits per pixel, only 1, 16, or 32 bits, unless I'm reading the docs incorrectly. So he'd still need about 50 MB for a 32-bit pixmap, which is certainly do-able.


long index= 0;
QImage image( 3172, 3172, QImage::Format_Indexed8 );
QVector<QRgb> colorTable(256);
for(int i=0;i<256;++i) { colorTable[i] = qRgb(i,i,i); }
image.setColorTable(colorTable);

for ( int i = 0; i < 3172; i++ )
{
for ( j = 0; j < 3172; j++ )
{
image.setPixel( i, j, data[index] );
index++;
}
}

mshemuni
4th April 2013, 13:59
Checked my code. That was absolutely wrong.
Found the code blow here (http://stackoverflow.com/questions/13670954/how-to-update-a-qpixmap-in-a-qgraphicsview-with-pyqt):



#!/usr/bin/env python

from PyQt4 import QtCore
from PyQt4 import QtGui

class Canvas(QtGui.QPixmap):
""" Canvas for drawing"""
def __init__(self, parent=None):
QtGui.QPixmap.__init__(self, 64, 64)
self.parent = parent
self.imH = 64
self.imW = 64
self.fill(QtGui.QColor(0, 255, 255))
self.color = QtGui.QColor(0, 0, 0)

def paintEvent(self, point=False):
if point:
p = QtGui.QPainter(self)
p.setPen(QtGui.QPen(self.color, 1, QtCore.Qt.SolidLine))
p.drawPoints(point)

def clic(self, mouseX, mouseY):
self.paintEvent(QtCore.QPoint(mouseX, mouseY))

class GraphWidget(QtGui.QGraphicsView):
""" Display, zoom, pan..."""
def __init__(self):
QtGui.QGraphicsView.__init__(self)
self.im = Canvas(self)
self.imH = self.im.height()
self.imW = self.im.width()
self.zoomN = 1
self.scene = QtGui.QGraphicsScene(self)
self.scene.setItemIndexMethod(QtGui.QGraphicsScene .NoIndex)
self.scene.setSceneRect(0, 0, self.imW, self.imH)
self.scene.addPixmap(self.im)
self.setScene(self.scene)
self.setTransformationAnchor(QtGui.QGraphicsView.A nchorUnderMouse)
self.setResizeAnchor(QtGui.QGraphicsView.AnchorVie wCenter)
self.setMinimumSize(400, 400)
self.setWindowTitle("pix")

def mousePressEvent(self, event):
if event.buttons() == QtCore.Qt.LeftButton:
pos = self.mapToScene(event.pos())
self.im.clic(pos.x(), pos.y())
#~ self.scene.update(0,0,64,64)
#~ self.updateScene([QtCore.QRectF(0,0,64,64)])
self.scene.addPixmap(self.im)
print('items')
print(self.scene.items())
else:
return QtGui.QGraphicsView.mousePressEvent(self, event)

def wheelEvent(self, event):
if event.delta() > 0:
self.scaleView(2)
elif event.delta() < 0:
self.scaleView(0.5)

def scaleView(self, factor):
n = self.zoomN * factor
if n < 1 or n > 16:
return
self.zoomN = n
self.scale(factor, factor)

if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
widget = GraphWidget()
widget.show()
sys.exit(app.exec_())
Modified it as this:


#!/usr/bin/env python

from PyQt4 import QtCore
from PyQt4 import QtGui
import h5py
import numpy


class Canvas(QtGui.QPixmap):
""" Canvas for drawing"""
def __init__(self, parent=None):
QtGui.QPixmap.__init__(self, 1000, 1000)
self.parent = parent
self.imH = 1000
self.imW = 1000
self.fill(QtGui.QColor(0, 255, 255))
self.color = QtGui.QColor(0, 0, 0)

def paintEvent(self, c, point=False):
if point:
p = QtGui.QPainter(self)
p.setPen(QtGui.QPen(QtGui.QColor(c, c, c), 1, QtCore.Qt.SolidLine))
p.drawPoints(point)

def clic(self, mouseX, mouseY, c):
self.paintEvent(c, QtCore.QPoint(mouseX, mouseY))


class GraphWidget(QtGui.QGraphicsView):
""" Display, zoom, pan..."""
def __init__(self):
QtGui.QGraphicsView.__init__(self)
self.im = Canvas(self)
self.imH = self.im.height()
self.imW = self.im.width()
self.zoomN = 1
self.scene = QtGui.QGraphicsScene(self)
self.scene.setItemIndexMethod(QtGui.QGraphicsScene .NoIndex)
self.scene.setSceneRect(0, 0, self.imW, self.imH)
self.scene.addPixmap(self.im)
self.setScene(self.scene)
self.setTransformationAnchor(QtGui.QGraphicsView.A nchorUnderMouse)
self.setResizeAnchor(QtGui.QGraphicsView.AnchorVie wCenter)
self.setMinimumSize(400, 400)
self.setWindowTitle("pix")

f = h5py.File('MSG3_201303312045.H5','r')
g=f['image4/image_data']
for i in range(50,3000):
for u in range(50,3000):
print(str(i) + " - " + str(u))
#self.im.setPen(QPen(QColor(qRgb(g[i,u],g[i,u],g[i,u])),1,Qt.SolidLine))
self.im.clic(i-50,u-50, g[i,u])
#self.fill(QtGui.QColor(g[i,u], g[i,u], g[i,u]))
self.scene.addPixmap(self.im)

def mousePressEvent(self, event):
if event.buttons() == QtCore.Qt.LeftButton:
pos = self.mapToScene(event.pos())
self.im.clic(pos.x(), pos.y())
#~ self.scene.update(0,0,64,64)
#~ self.updateScene([QtCore.QRectF(0,0,64,64)])
self.scene.addPixmap(self.im)
print('items')
else:
return QtGui.QGraphicsView.mousePressEvent(self, event)

def wheelEvent(self, event):
if event.delta() > 0:
self.scaleView(2)
elif event.delta() < 0:
self.scaleView(0.5)

def scaleView(self, factor):
n = self.zoomN * factor
if n < 1 or n > 16:
return
self.zoomN = n
self.scale(factor, factor)

if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
widget = GraphWidget()
widget.show()
sys.exit(app.exec_())


p.s: The file I attached is a group of a hdf5 file. So I read it directly from hdf5 for display.

Now there is another problem. It took ~19.5 minutes to read and display the file.
what should I do? Maybe using opengl would be a solution for this case.

p.s: It's not an 8 bit file. There is some number bigger than 255...

wysota
4th April 2013, 14:15
Now there is another problem. It took ~19.5 minutes to read and display the file.
what should I do? Maybe using opengl would be a solution for this case.
I think reading is the problem, not display.


p.s: It's not an 8 bit file. There is some number bigger than 255...
Yeah, well... so how does that relate to:


I have a huge(40MB) 8 bit(0-255) text file.

mshemuni
4th April 2013, 14:24
Well now I get it.
I thought there was numbers on the file ranged 0-255 so that meant 8 bit depth to me. It's about my English. I can't write what I meant yet. :)

Reading is not problem because I'm using h5py. I can display a number of the matrix in milliseconds.
The reading lines are:

f = h5py.File('MSG3_201303312045.H5','r')
g=f['image4/image_data']

Now g is a matrix. :)

wysota
4th April 2013, 20:08
So where does this 19 minutes come from?

mshemuni
4th April 2013, 20:56
When I try to get all numbers from matrix and paint a dot for each on screen, it takes 19 minutes...

wysota
4th April 2013, 21:17
So don't paint each dot separately.

mshemuni
5th April 2013, 19:40
I tried to calculate every 9 pixels value's average and paint it on one pixel. It made script works faster. But it still takes 12 minutes for complete painting. :(

wysota
5th April 2013, 21:28
No, you didn't understand me. You are currently painting one pixel at a time instead of setting all the pixels of the image at once (we have shown you how to do that faster using QImage::setPixel() and you can do it even faster with QImage::scanLine() or QImage::bits()). And also get rid of all the print statements, they are slowing down your script significantly.