Here is a small preview of "before" and "after". Sorry, cant post a fullsize picture, else DaimlerChrysler would kill me :grin:
Posted on 2003-05-13 15:12:57 by bazik
Humm.
The first thing to get rid of is get/setpixel - this is extremely slow. I suggest using CreateDIBSection, it gives you direct access to the pixel buffer.

Next, you have two for loops. Unless there's some special padding, you can make a single for loop - this will be faster.

Also, your snippet seems to do RGB-ish stuff. GIF is 8bpp, so you really ought to work on the data palettized. After all, MMX code would be able to process 8 pixels in parallel, which would be pretty damn fast.

Done properly, it shouldn't even take seconds to process a single image.
Posted on 2003-05-13 15:24:49 by f0dder
And now explain it so someone understands it who never worked with graphics manipulation in programming world :)

Gimme some pseudo code :P
Posted on 2003-05-13 15:28:51 by bazik
either you use GetDIBits+SetDIBits, or you make sure you have a DIB (CreateDIBSection). When filling your BITMAPINFO structure, be sure to specify height as a _negative_ value, to have a top-down image (old leftovers, sigh).

You might want to do 32bpp processing at first - it will allow you to specify RGB color values instead of palette indices, and will keep you from the hassle of setting up a bitmap palette :). Furthermore, you should be able to copy+paste arkanes MMX snippet, assuming of course it's bugfree.

Sorry that I can't post anything more complete right now, but I'm pretty tired - there should be enough hints to at least get you going :)
Posted on 2003-05-13 15:57:12 by f0dder
bazik,

I didn't read the entire thread, but if you just want to swap the colors so to speak, there is an API that will do it fast... by using BitBlt and the raster operation codes, ie. "SRCINVERT" (see: "Ternary raster operations", MSDN)...

http://www.google.com/url?sa=U&start=2&q=http://msdn.microsoft.com/library/en-us/gdi/pantdraw_73jn.asp&e=747

http://msdn.microsoft.com/library/en-us/gdi/bitmaps_0fzo.asp

also, SetPixelV is much faster than SetPixel

Brad

added: bazik, I can give you a PB example if you wish
Posted on 2003-05-13 16:57:32 by Brad

fastest? you use a 16meg LUT, that's hardly good for cache. You use loop, which is slow on a whole bunch of processors. Assuming 32bpp, you ought to mask off alpha bits (and if you planned to use that code on 24bpp... whoa).

Besides, there's other flaws. Like, you need a (2^24)*4 LUT, not one size (2^4)/4 . And your initialization is wrong too :). Come on comrade, you can do better than jokes like this :)


Code is linear, no jumps at all. So its 64MB LUT, my mistake. You can make 1KB LUT if you decode into R, G and B and then look them up separately.
Posted on 2003-05-13 17:04:17 by comrade
code is linear yes, but I think a 64meg LUT would kill any performance - naive Jcc code would probably end up faster.

Hm, 1kb LUT by decoupling R,G,B components? It's late, and I can't currently see how that would work - you need a full {R,G,B} triplet to do a lookup? There might be some smart idea I didn't think of.

However, for 8bpp a LUT might be an okay solution - 256 bytes should definitely fit into the cache :). Should still be clocked against CMOV and MMX versions though - both of those avoid conditional jumps and have very little cache overhead. Furthermore, the MMX code is simple to write and does 8 pixels at a time (unroll or use SSE2/MMX if you want to).
Posted on 2003-05-13 17:17:46 by f0dder
Most algorithms should be memory bound. I'd use MMX because it's simple. I wonder if an operation like this could be done by the graphics card?
Posted on 2003-05-13 17:39:26 by bitRAKE

code is linear yes, but I think a 64meg LUT would kill any performance - naive Jcc code would probably end up faster.

Hm, 1kb LUT by decoupling R,G,B components? It's late, and I can't currently see how that would work - you need a full {R,G,B} triplet to do a lookup? There might be some smart idea I didn't think of.

However, for 8bpp a LUT might be an okay solution - 256 bytes should definitely fit into the cache :). Should still be clocked against CMOV and MMX versions though - both of those avoid conditional jumps and have very little cache overhead. Furthermore, the MMX code is simple to write and does 8 pixels at a time (unroll or use SSE2/MMX if you want to).


Right. I guess cmov would be best approach.
Posted on 2003-05-13 18:07:32 by comrade
bazik, is this what you're looking for? :grin:



check bmpi.bmiHeader.biBitCount, this is for 32bpp only.

You can customize the 2 functions to suit your need. :)

this one changes the black background to 3366FF(somewhat blue -> ~70% of the window) and 0FF00h(Green) for the remaining black pixels.

tested on win2k sp3

I'm so ashamed of my code
ReplaceMem PROC USES ebx esi lpMem:DWORD, len:DWORD, value:DWORD

mov esi, lpMem
xor eax, eax
mov ebx, len
mov edx, value
@@:
mov ecx, DWORD PTR [esi+eax*4]
test ecx, ecx ;Do your comparison here
cmovz ecx, edx ;and change this to suit your needs
mov DWORD PTR [esi+eax*4], ecx
inc eax
cmp eax, ebx
jb @b
ret
ReplaceMem ENDP
much better. :grin:
Posted on 2003-05-13 19:44:23 by arkane

Most algorithms should be memory bound. I'd use MMX because it's simple. I wonder if an operation like this could be done by the graphics card?

A 64meg LUT would definitely be memory bound ^_^
Perhaps the GPU can do this stuff, but then you'd probably have to go DDraw or (perhaps more likely?) D3D. I assume this would also require a readback from the card, which is generally slow (or am I talking out of my ass?). Finally, it might not even be faster - you'd have to transfer the pixel data to the GPU, do the operation, and transfer back pixel data to system memory (if you plan on saving the data, anyway). But it's worth a try :)


Right. I guess cmov would be best approach.

Dunno... I'd think MMX would be at least as fast, perhaps faster - and that instruction set was introduced before CMOV. Anybody care to test?
Posted on 2003-05-14 01:59:01 by f0dder
If I understood properly, you want to change one single color for the whole image. If you're using 256 indexed-color mode, you can do this without modifying the data at all: just change the palette, that's what palettes are used for. For example, if the background color you use (black as I see) is index 0, go to your palette array and change the RGB values asociated to index 0, which are now (0,0,0), to something like (0ffh,0ffh,0ffh). Then refresh the BITMAP and the background will be white, without loops or mmx at all.


dibinf LABEL BITMAPINFO
BITMAPINFOHEADER < \
sizeof BITMAPINFOHEADER, \
SCREEN_WIDTH, \
-SCREEN_HEIGHT, \
1, \
8, \
BI_RGB, \
0, \
0, \
0, \
0, \
0>
My_Palette RGBQUAD 256 dup (<>)


The offset of the index you want to access is My_Palette. First three bytes are R,G,B (or B,G,R, I can never remember), fourth one is unused.

Regards,

Salieri
Posted on 2003-05-14 08:44:32 by Salieri

If I understood properly, you want to change one single color for the whole image. If you're using 256 indexed-color mode, you can do this without modifying the data at all: just change the palette, that's what palettes are used for. For example, if the background color you use (black as I see) is index 0, go to your palette array and change the RGB values asociated to index 0, which are now (0,0,0), to something like (0ffh,0ffh,0ffh). Then refresh the BITMAP and the background will be white, without loops or mmx at all.


dibinf LABEL BITMAPINFO
BITMAPINFOHEADER < \
sizeof BITMAPINFOHEADER, \
SCREEN_WIDTH, \
-SCREEN_HEIGHT, \
1, \
8, \
BI_RGB, \
0, \
0, \
0, \
0, \
0>
My_Palette RGBQUAD 256 dup (<>)


The offset of the index you want to access is My_Palette. First three bytes are R,G,B (or B,G,R, I can never remember), fourth one is unused.

Regards,

Salieri


Salieri,
thanks for the suggestion. I tested changing the palette in a graphic programm and it seems to work :) Gonna write up some test code now....
Posted on 2003-05-14 10:54:55 by bazik
heh, you don't need any more than a palette change?
:rolleyes:
Posted on 2003-05-14 10:58:56 by f0dder

heh, you don't need any more than a palette change?
:rolleyes:


Yep, seems like this does the trick :grin:

Didnt know that you can do that with a image :stupid:
Posted on 2003-05-14 11:01:32 by bazik
Yep the palette trick worked :) Thanks all for your help and sorry that I wasted your time ;)

The GIF files I have here are in GIF87a format, which is described here: http://www.w3.org/Graphics/GIF/spec-gif87.txt

All I need to do for my color changes is the following:

At 0xD change 0x000000 to 0xFFFFFF
At 0x6A change 0x00FFFF to 0xFF00FF
At 0x18D change 0xFFFFFF to 0x000000

I'll write a shell script for that, because that GIF files are generated on a HP-UX CAD Workstation... that way I even dont need to transfer the images to convert them :)
Posted on 2003-05-14 13:24:56 by bazik