Link to home
Start Free TrialLog in
Avatar of craigewens
craigewens

asked on

Pixel by pixel analysis of a picture...

Hi,

I've written a simple piece of code to go through and analyse each pixel, for colour, in a picture.
The picture is loaded into my form with the use of a picturebox. The picture is quite complex, but is only made of black and white colours.
When the pixel colour doesn't equal white (16777215) I use the x,y co-ordinates of that pixel and write them to a file.
I then use this file to re-generate the picture in one of our companies in-house applications.

Here is the code that determines the colour of every pixel:
[code]
    For i = 0 To Picture1.Width -1 Step 1
        For j = 0 To Picture1.Height -1 Step 1
            Colour = Picture1.Point(i, j)
            If Colour <> 16777215 Then f.writeline ("    RectAbs " & i & "," & j & " 1,1")
        Next j
    Next i
[/code]

The problem is that my picture is way to big to show it all at once on screen. Because my picturebox is smaller than the size of the picture, when analysing a pixel outside of the picturebox frame i get an colour that doesn't relate to what the picture should be showing.

Can anyone suggest a better way of going though each and every pixel of my picture, without having to actually show the whole picture on screen? If there are better ways of doing this that include not loading the picture into my program, then the picture was originally in a HPGL format which i converted in TIFF. I guess i could convert it into another format if it makes things easier.

Any sample/snipets of code would be greatly appreciated in getting me started.

Thanks very much.
ASKER CERTIFIED SOLUTION
Avatar of zzzzzooc
zzzzzooc

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of craigewens
craigewens

ASKER

Thanks for the rapid reply.
Unfortunatly though i'm having some dificulties in getting it to recognise any picture files i through at it.
I take my TIF and save as a 24bit BMP, I save it as a 24bit JPG and neither of these formats seem to work. Each time lBytesPerPix returns a 2.

Even though the programs i use to save the pictures say they're 24bit, the code is not picking this up. I followed the link you kindly provided and i presume my problem is related to this comment...

[quote]A 256 color Bitmap has 1 byte per pixel, but this byte is a palette index, not a color. So you need to convert colors into palette indexs before setting the array. The same applies to 16bit HiColor bitmaps.[/quote]

I presume 2bytes per pixel is 16bit HiColour?

The only gfx programs i really have access to at work is Paint and MS Photo Editor (MS Office addon)... surely these should be able to produce valid 24bit images when they say they are?
I opened an 8-bit (1 byte per pixel) image in MS Paint, saved it as 24-bit bitmap and it worked (was 3 bytes per pixel). If you can manage to get the image converted correctly, here's an optimized version...

Form1:
============

Option Explicit

Private Type BITMAP
    bmType As Long
    bmWidth As Long
    bmHeight As Long
    bmWidthBytes As Long
    bmPlanes As Integer
    bmBitsPixel As Integer
    bmBits As Long
End Type

Private Declare Function GetObjectAPI Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Function SetPixel Lib "gdi32" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long, ByVal crColor As Long) As Long
Private Sub Form_Load()
    Dim BMPLoad As StdPicture, BMPInfo As BITMAP, BMPBits() As Byte
    Dim lBytesPerPix As Long
    Dim lPosX As Long, lPosY As Long
    Dim iR As Integer, iG As Integer, iB As Integer, lPixel As Long
    Me.AutoRedraw = True
    Set BMPLoad = LoadPicture("c:\test.bmp")
    If GetObjectAPI(BMPLoad.Handle, Len(BMPInfo), BMPInfo) <> 0 Then
        ReDim BMPBits(1 To BMPInfo.bmWidthBytes, 1 To BMPInfo.bmHeight)
        If GetBitmapBits(BMPLoad.Handle, BMPInfo.bmWidthBytes * BMPInfo.bmHeight, BMPBits(1, 1)) <> 0 Then
            lBytesPerPix = (BMPInfo.bmWidthBytes \ BMPInfo.bmWidth)
            If lBytesPerPix = 3 Then
                For lPosX = LBound(BMPBits, 1) To UBound(BMPBits, 1) - lBytesPerPix Step lBytesPerPix
                    For lPosY = LBound(BMPBits, 2) To UBound(BMPBits, 2)
                        iR = BMPBits(lPosX + 2, lPosY)
                        iG = BMPBits(lPosX + 1, lPosY)
                        iB = BMPBits(lPosX, lPosY)
                        lPixel = RGB(iR, iG, iB)
                        Call SetPixel(Me.hDC, lPosX / lBytesPerPix, lPosY, lPixel)
                    Next lPosY
                Next lPosX
            Else
                MsgBox "Not supported."
            End If
        End If
    End If
End Sub

===========

I can't seem to implement getting the color palette with this method but it seems fine to be able to use a 24-bit image instead.
Even with your optimized code, I was still unable to load in my 24bit file. I added a label to the form to print out the lBytesPerPix, BMPInfo.bmWidthBytes and BMPInfo.bmWidth.

On my machine it returned:
lBytesPerPix = 2
BMPInfo.bmWidthBytes = 516
BMPInfo.bmWidth = 157

On another machine it returned:
lBytesPerPix = 3
BMPInfo.bmWidthBytes = 774
BMPInfo.bmWidth = 157

and on another machine it returned:
lBytesPerPix = 1
BMPInfo.bmWidthBytes = 258
BMPInfo.bmWidth = 157


Eventually the coin dropped and I realised each of the computers were running Windows in different graphics modes (256 colours (ack!), 16bit and 32bit). This is why the same code worked on one machine and not on another.

I didn't realise such an error would occur because of this, even though the BMP file I used on each of the computers was exactly the same. I presumed since we were using Direct Memory Access and nothing was actually being displayed, it wouldn't be effected like this.

I guess my problem now with this method is that I can't guarantee what graphics mode the computer running my application will have set. Sure I can report a message informing them to change it, but it's not very slick is it :(
After a little more investigating, perhaps the graphics mode isn't the problem...

On my machine i can now be in 256 colours, 16bit or 32bit and still get
lBytesPerPix = 2
BMPInfo.bmWidthBytes = 516
BMPInfo.bmWidth = 157

Is some initialisation of the file is required after altering the gfx mode perhaps?
This job is getting rather confusing now...



Should i increase the number of points for this question do you think?
I wrote the above comment and decided to try my code on another computer.. i compile into an exe and decide to run it... this time it works! Without changing resolution or anything.. arrggghh!

Can anyone explain what the issue is with this?
This not being able to edit previous post is really anoying...  :)


Anyway....

zzzzzooc, you've been more than helpful and i've finally got to grips with what's going on with your code and my application.
You are getting the points from this thread for definate.

Before i close this thread by giving you the points though, could you please explain why i have to compile and use the executable file for it to work? If you're unsure or plain dont wish to, totally up to you, just say so...  Either way the points are yours.
Yeah.. they do need a Edit/Delete option for your own posts (except for deleting questions yourself).. and if they do have one.. they need it more visible :P

>> why i have to compile and use the executable file for it to work?

I tested all of my examples through the IDE and they worked fine (I never even tried compiling them lol). If you're not using XP or VB6 then there could be incompatibilities or issues I haven't thought of but I'm not sure about any of the problems you were experiencing. Bitmaps should be stored as 24-bit but your display/graphics adapter may automatically convert them if they don't support those bit depths. So if you don't support 24/32 bit, they may end up completely different. I'm not too aware on the complications between screen depths and display/graphic adapaters (lack of testing on multiple systems) so I can't help.
Sound advice, thanks very much.
I've increased the points to 200 also to show my appreciation.

Thanks again!

Craig.