Solved Weird QImage pixel manipulation issue.
-
Hello,
sorry, my actual code was different. The image is assured to be 32bpp, therefore I actually used
uint *end = ptr + (inv.byteCount() / 4);
but the issue remains. I tried to save my QPixmap to file before rendering it and it looks just fine, that means my manipulation can not be the issue here. :(
-
@Nicolas-Kogler Does your pixmap have a transparent background?
-
@jsulm said in Weird QImage pixel manipulation issue.:
@Nicolas-Kogler Does your pixmap have a transparent background?
Indeed. It needs to have a transparent background for the algorithm to work dynamically and in every situation possible. Is that an issue?
I believe that semi-transparency is the issue by now, but forcing the background to be white (QPainter::setBackground & QPainter::setBackgroundMode) in the paintEvent didn't help either.
Of course, I could blit the QPixmap on a plain white image and draw that in the end, but this is kinda hacky and also quite costly when done multiple times or with larger images.
-
@Nicolas-Kogler
Just iterate the image through the API instead of the internal data. E.g.:QPixmap modify(const QImage &source) { qint32 width = source.width(), height = source.height(); QImage result(width, height, source.format()); for (qint32 y = 0, y < height; y++) { for (qint32 x = 0; x < width; x++) { QRgb pixel = source.pixel(x, y); Q_ASSERT(0x132 - qRed(pixel) <= 0xFF && 0x132 - qGreen(pixel) <= 0xFF && 0x132 - qBlue(pixel) <= 0xFF); pixel = qRgb(0x132 - qRed(pixel), 0x132 - qGreen(pixel), 0x132 - qBlue(pixel)); result.setPixel(x, y, pixel); } } return QPixmap::fromImage(result); }
And I don't understand what this is supposed to do exactly:
*ptr++ += 0x00333333;
why add
0x00333333
, what's the significance? You do understand that there will be shifting if the value overflows ...? -
Hello kshegunov,
isn't setPixel costly? To answer your question: Only pure black images are passed to this function. The loop continuously fetches the RGBA data (i.e. 0xFF000000) and adds 0x00333333 to it -> 0xFF333333, results in a slightly brighter picture.
I will try your method nevertheless and set this topic as "solved" if I don't find any better one. Thanks!
-
If that is the only case then it's much more efficient to use the colour table
inv.convertToFormat(QImage::Format_Indexed8); const int colCount=inv.colorCount(); for(int i=0;i<colCount;++i){ if(inv.color(i)==qRgba(0,0,0,0xFF)){ inv.setColor(i,qRgba(0x33,0x33,0x33,0xFF)); break; } }
-
That actually is a great idea VRonin, as flat-styled images will never really contain more than 256 colors!
Solved :).
-
@Nicolas-Kogler said in Weird QImage pixel manipulation issue.:
isn't setPixel costly?
Depends on your definition of costly. A function call, couple of
if
s and aswitch
I don't consider to be much on the costly side. -
We are not necessarily talking about small images here. I believe setPixel is costly when big images are involved. But thanks for that solution, too. May come in handy for small images later! :)
-
As one Donald Knuth once notably remarked:
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."Which I happen to agree with. So before you know that the call to
setPixel()
is a bottleneck I advise you just forget this (really) tiny inefficiency. -
@kshegunov said in Weird QImage pixel manipulation issue.:
As one Donald Knuth once notably remarked:
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."Which I happen to agree with. So before you know that the call to
setPixel()
is a bottleneck I advise you just forget this (really) tiny inefficiency.I agree, but as Niklaus Wirth once stated:
'Software is getting slower more rapidly than hardware is getting faster.'
I tested it now, both algorithms work and the method with 'scanline' and 'bits' is faster, so why wouldn't I take the faster one?btt:
I finally found the issue (I felt like this could be it for a while) for the weird rendering, but I cannot really explain why it happened, given the fact that 'c' is copied in invertImage():void setImage(const QPixmap &img) { QImage c = img.toImage(); // ... do some pixel fetching (but not manipulating) ... m_pm = QPixmap::fromImage(invertImage(c)); }
now with
void setImage(const QImage &c) { // ... do some pixel fetching ... m_pm = QPixmap::fromImage(invertImage(c)); }
it just works fine.
-
@Nicolas-Kogler said in Weird QImage pixel manipulation issue.:
I tested it now, both algorithms work and the method with 'scanline' and 'bits' is faster, so why wouldn't I take the faster one?
Few reasons (whether they're good is up to you to decide):
- It depends on the internal representation of the data inside
QImage
which isn't guaranteed to be compatible between versions, while the Qt API is binary compatible between minor versions (that translates to years). - It's a (tragic) fact of life that code is read much more than it's written, so one'd be wise to opt for more readable (and type-safe) code as every opportunity presents itself.
- Faster is a relative term - faster compared to what? Knuth's whole point is that you can spend months making a piece of code to run 10% faster, but if that piece of code carries 10% of the total execution time, in reality you've optimized only to remove a meager 1% of execution time. Ultimately, it boils down to profiling, finding the bottlenecks and finally removing them.
PS.
Talking about micro optimizations I'd suggest changing:inv.byteCount() / 4
to:
inv.byteCount() >> 2
it isn't that clear and pretty though, is it?
- It depends on the internal representation of the data inside
-
Bitshifting is just plain beautiful <3
Jokes aside, of course you are totally correct. I implemented the same algorithm twice because I thought that my initial issue was caused by that. Anyways, now I am just using pixel and setPixel to interact with the data, because I agree on the readability reason with you.
@kshegunov said in Weird QImage pixel manipulation issue.:
Faster is a relative term - faster compared to what? Knuth's whole point is that you can spend months making a piece of code to run 10% faster, but if that piece of code carries 10% of the total execution time, in reality you've optimized only to remove a meager 1% of execution time. Ultimately, it boils down to profiling, finding the bottlenecks and finally removing them.
This is also a good point, but I guess it only applies to companies which actually only have spare development time. This is a hobby project, therefore I have plenty of time to try different stuff and play around with the features of Qt. Not to mention that I am 18 years old only and need to gain experience working with the Qt framework.
We shouldn't abuse this thread for these kinds of discussions anymore. You can always send me a private message, if you want. :)
-
@Nicolas-Kogler said in Weird QImage pixel manipulation issue.:
We shouldn't abuse this thread for these kinds of discussions anymore.
I tend to wander off, so that happens to me a lot ... sorry.
-
Sorry to put this back on top, but for anyone who has the same problem as I had:
The reason for the messed-up background was that after copying the image, Qt somehow converted it to a premultiplied-alpha format. Hence attempting to edit the pixels was disastrous. A call to 'convertToFormat(QImage::Format_ARGB32)' after 'copy()' should do it :).