reading jpg image pixel values

Posted on 2004-11-30
Last Modified: 2008-02-01
OK, here is what I have...

I have a program that scans via twain image driver.

We have what is called a routing slip similar to a scantron where people are coloring in circles.

I want to be able to read pixel values from any point.  because we are scanning at such a high resolution the image goes outside of the visible picture box.  

my problem is that I cannot read any part of an image that is not visible in a picture box.

my goal is to read pixel rgb values given an x,y coordinate in pixels for any point in the image without dealing with a picture box or external dll objects.

we are using this object as an activeX web object.

Thank you so much for all your help
Question by:icredes
    LVL 32

    Expert Comment

    How does the image get to the picturebox?
    Are you passed any info about the image dimensions?
    LVL 1

    Author Comment

    the only information that I have is the file path
    LVL 28

    Expert Comment

    I assume the image is hidden, though, yes?  Why not set the Picturebox AutoSize property to True?
    LVL 1

    Author Comment

    the issue is that I need to be able to view the image at 100% 300 dpi

    getting the image dimentions is not too difficult.

    my concern is getting the pixel values

    I am going to assume that the image is the correct size.
    LVL 1

    Author Comment

    the autosize feature is interesting, but the point here is not to use the picture box

    even if I get the correct size, the image is too big to fit on the screen.

    is there another way....

    lets assume that I were to do this in a module without the use of a form if possible.
    LVL 32

    Accepted Solution

    You can use a memoryDC to load the picture into.  Then you can read the pixels using the GetPixel API.  All of the following code can be adapted for use in a module because no picturebox is used.

    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 CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
    Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
    Private Declare Function GetObjectAPI Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
    Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
    Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long

    Private Sub Command1_Click()

        Dim pic As StdPicture
        Dim memDC As Long
        Dim px As Long
        Dim bm As BITMAP
        'Load a picture
        Set pic = LoadPicture("c:\thumb.jpg")
        'Create a DC compatible with the screen
        memDC = CreateCompatibleDC(0)
        'Select the picture into the DC
        Call SelectObject(memDC, pic.Handle)
        'Get the bitmap info
        Call GetObjectAPI(pic.Handle, LenB(bm), bm)
        Debug.Print "Picture dimensions: ", bm.bmHeight, bm.bmWidth
        'Here we read the center pixel color using GetPixel
        px = GetPixel(memDC, bm.bmWidth / 2, bm.bmHeight / 2)
        Debug.Print "The color is " & Hex(px)
        'Done, Clean Up
        Call DeleteDC(memDC)

    End Sub

    LVL 17

    Expert Comment

    @ icredes

    The following program needs a source Picbox(no matter if visible or invisible) and a destination picbox(visible).

    It works without API. You will get all the r-g-b values of the picture and of each pixel.

    'Needs 2 Pictureboxes
    Const Pic = "C:\WINDOWS\Desktop\LAPTOP.JPG"

    Private Sub Form_Activate()
    AutoRedraw = -1: Picture2.ScaleMode = 3
    Move 0, 0: Picture1.BackColor = vbBlue
    Picture1.Move 15 * 70, 15 * 15, 15 * 360, 15 * 290
    Picture1.BorderStyle = 0: Picture1.ScaleMode = 3
    Picture2.BorderStyle = 0: Picture1.BackColor = vbWhite: Picture2.BackColor = vbWhite
    Picture2.Move Picture1.Left + Picture1.Width + 15 * 9, 15 * 15, 15 * 30, 15 * 18
    Picture1.Picture = LoadPicture("C:\WINDOWS\Desktop\LAPTOP.JPG")
    For YY = 0 To Picture1.Picture.Width
    For XX = 0 To Picture1.Picture.Height

    Picture2.PaintPicture Picture1.Picture, 0, 0, 1, 1, XX, YY, 1, 1

    col = Picture2.Point(0, 0) 'BGR
    Picture2.BackColor = col

    b = (col And 16711680) / 65536 '     16711680  = FF0000
    g = (col And 65280) / 256 '          65280     = FF00
    r = col And 255

    MsgBox XX & "  ,  " & YY & vbCrLf _
           & "r , g , b" & vbCrLf & r & " , " & g & " , " & b

    Next: End

    End Sub
    LVL 17

    Expert Comment

    I found a good way to do this.   What it does is map an array's memory to point to a picture's memory.  But the cute thing is that you map a UDT array so that you don't have to do any maths to get the pixel values. This makes it very fast.

    I took the concept from here:

    (Also search goolge for safearray2d for more inhfo/examples like the same.

    And then made the leap into using a UDT array. You can either use a 2 dimensional array, or in some cases for faster image processing, you can use a single dimensional array.

    I renamed the class zPicArray, so for example:

    Dim PA as zPicArray

    Set picAnyPic.Picture = LoadPicture("C:\........jpg")
    Set PA = New zPicArray
    PA.LoadImage picAnyPic
    Pa.ProcessImage Actions.ConvertToGreyScale

    ' extract from the class (single dimension version) the following converts a colour image to greay scale

    Sub ProccessImage(Action As Actions)

    Dim cp As Long
    Dim Av As Long
    Dim bt As Byte
    Dim GreyFactor As Single

    GreyFactor = 0.333333
    cp = 0

    Select Case Action
        Case Is = Actions.ConvertToGreyScale

        ' loop through image
        Do While cp < aSize ' asize is the size of the pic in pixels
            Av = (0& + Data(cp).Red + Data(cp).Green + Data(cp).Blue) * GreyFactor
            bt = Av
            ' Save the greyed pixel values back into the picture box
            Data(cp).Red = bt
            Data(cp).Green = bt
            Data(cp).Blue = bt
            cp = cp + 1
    End Select

    End Sub

    In you case you may wish to stay with 2 dim array. So to modify the example from visualbasicforum to use UDT's you need:

    Private Type PixelDef
      Blue As Byte
      Green As Byte
      Red As Byte
    End Type

    Private Data() As PixelDef ' was byte

    And in the LoadImage sub change

    .cbElements = 3 ' was 1 to point to a byte

    If you need any more info with this concept.
    LVL 17

    Expert Comment

    And also in the loadimage change:

    .Bounds(1).cElements = BMP.bmWidthBytes


    .Bounds(1).cElements = BMP.bmWidth

    So after your loadimage you can then loop image.  I posted a single dim example, here is a 2 dim example of looping through an image:

    ' filter out red
    For y = 0 To mvarUBoundY
        For x = 0 To mvarUBoundX
           Datal(x,y).Red = 0
    LVL 1

    Author Comment

    Erick37  you nailed it

    that works great for me...thanks

    Featured Post

    How to run any project with ease

    Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
    - Combine task lists, docs, spreadsheets, and chat in one
    - View and edit from mobile/offline
    - Cut down on emails

    Join & Write a Comment

    When designing a form there are several BorderStyles to choose from, all of which can be classified as either 'Fixed' or 'Sizable' and I'd guess that 'Fixed Single' or one of the other fixed types is the most popular choice. I assume it's the most p…
    This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
    As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
    Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…

    729 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    19 Experts available now in Live!

    Get 1:1 Help Now