Announcement

Collapse
No announcement yet.

Counting dots in an image (birds, reindeer...)

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Counting dots in an image (birds, reindeer...)

    Looking at a picture of a flock of birds on the wing, I wondered how the image could be analysed to count them - black shapes on a blue background. I'm sure that this is used in industry and in science - but what is the algorithm?

    The black shapes are of course irregular - but let's simplify it to say that one black shape = 1 reindeer. I mean bird. More sherry, Santa?
    Last edited by Chris Holbrook; 25 Dec 2008, 04:07 PM.

  • #2
    Chris,
    if the contrast is good enough then try this code. It was written to count storm systems in a satellite picture but it should be easily modified to count birds (small radius) or swarms (larger radius) if they have enough contrast against the background.
    The attached .GIF needs to be converted to a .BMP file and placed in the c:\ directory as storms5.bmp for the demonstration to work as it's written.
    Press a key to do each step of the process in turn and display the results.

    Paul.

    Code:
    'PBCC5 program
    #BREAK ON
    #INCLUDE "win32api.inc"
    
    %showscreenupdate=1
    
    FUNCTION PBMAIN() AS LONG
    REGISTER pix1 AS LONG
    REGISTER y AS LONG
    
    Storm$="c:\storms5.bmp"
    radius&=1
    
    
    'get the size of the bitmap
    nFile& = FREEFILE
    OPEN Storm$ FOR BINARY AS nFile&
    GET #nFile&, 19, nWidth&
    GET #nFile&, 23, nHeight&
    CLOSE nFile&
    
    'load the bitmap of the storm system
    GRAPHIC BITMAP LOAD Storm$,nWidth&,nHeight&,%BLACKONWHITE TO hBmp1???
    
    GRAPHIC ATTACH hBmp1???,0
    GRAPHIC GET BITS TO Image1$
    
    xsize& = CVL(image1$,1)
    ysize& = CVL(image1$,5)
    
    'show it on screen so I can see the effect of each stage of processing
    GRAPHIC WINDOW "Storm ID",1,1,xsize&,ysize& TO hWin1???
    GRAPHIC ATTACH hWin1???,0 ,REDRAW
    
    GRAPHIC COPY hBmp1???,0
    
    DIM bmp(xsize&-1,ysize&-1) AS LONG AT STRPTR(Image1$)+8
    
    PRINT xsize&,ysize&
    PRINT LEN(image1$)
    
    GRAPHIC REDRAW
    
    CONSOLE SET LOC 800,0
    CONSOLE SET FOCUS
    
    PRINT "Original image"
    WAITKEY$
    PRINT "Removing non black/white pixels and improving contrast"
    'remove all non black/white pixels
    FOR x& = 0 TO xsize&-1
        FOR y& = 0 TO ysize&-1
            pix1&=bmp(x&,y&)
    
            r&=pix1& AND 255
            g&=(pix1& AND &h0000ff00) \256
            b&=(pix1& AND &h00ff0000) \ 65536
            brightness& = r&+b&+g&
    
            IF brightness& > 700 THEN
                GRAPHIC SET PIXEL (x&,y&),%WHITE
                bmp(x&,y&)=%WHITE
            ELSE
                GRAPHIC SET PIXEL (x&,y&),%BLACK
                bmp(x&,y&)=%BLACK
    
            END IF
        NEXT
    #IF %DEF (%showscreenupdate)
        GRAPHIC REDRAW
    #ENDIF
    
    NEXT
    GRAPHIC REDRAW
    
    WAITKEY$
    PRINT "Merging storms within range into systems"
    
    'find those storms within the specified range and merge them into systems
    FOR x& = 0 TO xsize&-1
        FOR y& = 0 TO ysize&-1
           ' graphic get pixel (x&,y&) to pix1&
            pix1&=bmp(x&,y&)
            IF pix1& = %WHITE THEN
                GRAPHIC ELLIPSE (x&-radius&,y&-radius&) - (x&+radius&,y&+radius&) ,%YELLOW,%YELLOW,0
    
            END IF
    
        NEXT
    
    #IF %DEF (%showscreenupdate)
        GRAPHIC REDRAW
    #ENDIF
    
    NEXT
    GRAPHIC REDRAW
    
    WAITKEY$
    PRINT "Identifying individual systems"
    'identify each system from the others
    NextColour&=1
    DIM systemlocationx(10000) AS LONG
    DIM systemlocationy(10000) AS LONG
    
    FOR x& = 0 TO xsize&-1
        FOR y& = 0 TO ysize&-1
            GRAPHIC GET PIXEL (x&,y&) TO pix1&
            IF pix1& = %YELLOW THEN
                GRAPHIC PAINT (x&,y&),NextColour&,%BLACK
                systemlocationx(NextColour&)=x&
                systemlocationy(NextColour&)=y&
    
                NextColour&=NextColour&+1
            END IF
        NEXT
    
    #IF %DEF (%showscreenupdate)
        GRAPHIC REDRAW
    #ENDIF
    
    NEXT
    GRAPHIC REDRAW
    
    PRINT NextColour&-1;"Sytems found"
    WAITKEY$
    PRINT "Calculating size and centre of each system"
    SystemLimit&=NextColour&
    
    'find centre of each system
    DIM CofGx(SystemLimit&) AS SINGLE
    DIM CofGy(SystemLimit&) AS SINGLE
    DIM CofGpoints(SystemLimit&) AS SINGLE
    
    
    FOR x& = 0 TO xsize&-1
        FOR y& = 0 TO ysize&-1
            pix1&=bmp(x&,y&)
            IF pix1& = %WHITE THEN
    
                GRAPHIC GET PIXEL (x&,y&) TO pix1&
                CofGx(pix1&)=CofGx(pix1&)+x&
                CofGy(pix1&)=CofGy(pix1&)+y&
                CofGpoints(pix1&) = CofGpoints(pix1&)+1
            END IF
        NEXT
    NEXT
    GRAPHIC REDRAW
    
    PRINT "Removing systems smaller than some limit (for now make it 1000 pixels)"
    MaxSize&=0
    FOR r&= 1 TO SystemLimit&
        IF CofGpoints(r&)>MaxSize& THEN MaxSize&=CofGpoints(r&)
    NEXT
    PRINT "Largest System is";MaxSize&;"points"
    
    FOR r&= 1 TO SystemLimit&
        IF CofGpoints(r&)< 1000 THEN
            CofGpoints(r&)=0
            GRAPHIC PAINT (systemlocationx(r&),systemlocationy(r&)), %BLACK,%BLACK
        END IF
    NEXT
    GRAPHIC REDRAW
    
    
    WAITKEY$
    PRINT "Find edges of remaining storm systems"
    
    'edge detect the systems and draw the yellow line
    FOR x& = 1 TO xsize&-2
        FOR y& = 1 TO ysize&-2
            GRAPHIC GET PIXEL (x&,y&) TO pix1&
    
            IF pix1& = %BLACK THEN
                GRAPHIC GET PIXEL (x&-1,y&-1) TO pix1& :IF pix1&<>%BLACK AND pix1&<>%YELLOW THEN GRAPHIC SET PIXEL (x&,y&),%YELLOW:EXIT IF
                GRAPHIC GET PIXEL (x&  ,y&-1) TO pix1& :IF pix1&<>%BLACK AND pix1&<>%YELLOW THEN GRAPHIC SET PIXEL (x&,y&),%YELLOW:EXIT IF
                GRAPHIC GET PIXEL (x&+1,y&-1) TO pix1& :IF pix1&<>%BLACK AND pix1&<>%YELLOW THEN GRAPHIC SET PIXEL (x&,y&),%YELLOW:EXIT IF
                GRAPHIC GET PIXEL (x&-1,y&  ) TO pix1& :IF pix1&<>%BLACK AND pix1&<>%YELLOW THEN GRAPHIC SET PIXEL (x&,y&),%YELLOW:EXIT IF
                GRAPHIC GET PIXEL (x&+1,y&  ) TO pix1& :IF pix1&<>%BLACK AND pix1&<>%YELLOW THEN GRAPHIC SET PIXEL (x&,y&),%YELLOW:EXIT IF
                GRAPHIC GET PIXEL (x&-1,y&  ) TO pix1& :IF pix1&<>%BLACK AND pix1&<>%YELLOW THEN GRAPHIC SET PIXEL (x&,y&),%YELLOW:EXIT IF
                GRAPHIC GET PIXEL (x&  ,y&+1) TO pix1& :IF pix1&<>%BLACK AND pix1&<>%YELLOW THEN GRAPHIC SET PIXEL (x&,y&),%YELLOW:EXIT IF
                GRAPHIC GET PIXEL (x&+1,y&+1) TO pix1& :IF pix1&<>%BLACK AND pix1&<>%YELLOW THEN GRAPHIC SET PIXEL (x&,y&),%YELLOW:EXIT IF
    
    
            END IF
        NEXT
    
    #IF %DEF (%showscreenupdate)
        GRAPHIC REDRAW
    #ENDIF
    
    NEXT
    GRAPHIC REDRAW
    WAITKEY$
    PRINT "overlay storm systems with original image"
    
    
    'GOTO skip    'remove this GOTO if you want the output to look like the original with the clouds in the final picture (as your first example)
                 'leave it in if you want the output to just include the system outlines, not the clouds within (as you second example)
    
    'remove all the unwanted colours and overlay with original bitmap
    FOR x& = 0 TO xsize&-1
        FOR y& = 0 TO ysize&-1
            GRAPHIC GET PIXEL (x&,y&) TO pix1&
            IF (bmp(x&,y&)=%WHITE) AND (pix1& <> %BLACK) THEN
    
                    GRAPHIC SET PIXEL (x&,y&),%WHITE
    
            ELSE
    
                IF pix1& <> %YELLOW THEN
                    GRAPHIC SET PIXEL (x&,y&),%BLACK
                END IF
            END IF
    
    
    
        NEXT
    
    #IF %DEF (%showscreenupdate)
        GRAPHIC REDRAW
    #ENDIF
    
    NEXT
    GRAPHIC REDRAW
    WAITKEY$
    GOTO skip2
    
    skip:
    'Instead of an overlay, just remove the unwanted colours :remove all the unwanted colours and overlay with original bitmap
    FOR x& = 0 TO xsize&-1
        FOR y& = 0 TO ysize&-1
            GRAPHIC GET PIXEL (x&,y&) TO pix1&
    
            IF pix1& <> %YELLOW THEN GRAPHIC SET PIXEL (x&,y&), %BLACK
    
        NEXT
    
    #IF %DEF (%showscreenupdate)
        GRAPHIC REDRAW
    #ENDIF
    
    NEXT
    GRAPHIC REDRAW
    WAITKEY$
    
    skip2:
    
    
    PRINT "Show storm centres"
    
    'plot the centre of each system
    FOR r& = 1 TO SystemLimit&
        SystemSize&=CofGpoints(r&)
        BlueDotSize&=SQR(CofGpoints(r&))/10
        IF CofGpoints(r&)<>0 THEN
            'found a system centre
            GRAPHIC ELLIPSE (CofGx(r&)/CofGpoints(r&)-BlueDotSize&, CofGy(r&)/CofGpoints(r&)-BlueDotSize&) - (CofGx(r&)/CofGpoints(r&)+BlueDotSize&, CofGy(r&)/CofGpoints(r&)+BlueDotSize&),%BLUE,%BLUE,0
        END IF
    NEXT
    
    
    
    GRAPHIC REDRAW
    WAITKEY$
    
    GRAPHIC SAVE "c:\stormoutput.bmp"
    
    END FUNCTION
    Attached Files

    Comment


    • #3
      Thanks for that Paul, fascinating stuff.

      I need to do some work on the image before your app. can use it - at the moment all the birds vanish in the first pass! So I'm attempting to find and rank all the colours by "number of pixels of same colour in the image". Then starting with the lightest colour, turn all pixels of that colour white, and continue until the image starts to appear depleted of birds. I can't think how else to calibrate it.

      Last edited by Chris Holbrook; 25 Dec 2008, 06:27 PM. Reason: attempt to add image

      Comment


      • #4
        The problem I see, Chris, after looking at the image blown a number of times is the starlings are not a single color. IOW, looking at individual pixels (image is 800x600) they are a range of (blue)greys. Some are only a couple pixels across and some are groups of px, 3 or 4 high x 6 or more across. Ans some are just single px.

        Maybe a higher res picture. (?) Or a BW version instead of color (better contrasts(?))

        Another thought is to maybe examine pxl and considering anything darker than RGB (152, 168, 193) (12,691,608) a starling as that *appears* (to me) the darkest sky color.

        Sort of
        Code:
        Darkest_Sky_Color = RGB (152, 168, 193)
         
         
        If px > Darkest_Sky_Color and Last_Px = < Darkest_Sky_Color& then incr starlings
         
        Last_Px = This_Px
        ===================================
        "When you have to kill a man,
        it costs nothing to be polite."
        Sir Winston Churchill (1874-1965)
        ===================================

        Just a thought. Anyway a neat exercise to play with.
        Last edited by Gösta H. Lovgren-2; 25 Dec 2008, 10:05 PM.
        It's a pretty day. I hope you enjoy it.

        Gösta

        JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
        LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

        Comment


        • #5
          Just made a BW copy. Should be much easier to count (except for a few on the edges/corners). Only two colors.

          Cheating on the example though.

          ======================================================
          "I don't want to achieve immortality through my work;
          I want to achieve immortality through not dying."
          Woody Allen (1935-)
          ======================================================
          Attached Files
          It's a pretty day. I hope you enjoy it.

          Gösta

          JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
          LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

          Comment


          • #6
            Originally posted by Gösta H. Lovgren-2 View Post
            Just made a BW copy.
            Gösta, Thanks for the BW copy - how did you make it?

            Comment


            • #7
              remove sig

              Chris --

              In that picture, some birds pretty clearly ovlap so a larger single dark spot probably represents 2 or more birds. Some of the clumps are pretty large.

              Why not simply count the number of dark pixels in the picture, then divide by your best guess of pixels-per-bird?

              -- Eric
              Last edited by Eric Pearson; 26 Dec 2008, 10:32 AM.
              "Not my circus, not my monkeys."

              Comment


              • #8
                The brightness of the image varies a lot so it's difficult to set an overall threshold to say a point darker than the threshold is a bird and if it's lighter then it's sky.
                Instead, you need to vary the threshold throughout the picture by looking, e.g. at a 100x100 pixel block and detecting birds in that block, move on a little and repeat in the next block which will have a different overall brightness and a different threshold. This will be quite a slow process.

                The attached code uses a very crude approximation by just looking at 1 pixel either side and deciding if the change in brightness across those 3 pixels is high enough to suspect a bird. It does quite a good job and is quick but is not perfect.

                EDIT: The one pixel either side method isn't as good as it first looked. Things will have to be done in blocks

                Paul.
                Code:
                'PBCC5 program
                #BREAK ON
                #INCLUDE "win32api.inc"
                
                %showscreenupdate=1
                
                FUNCTION PBMAIN() AS LONG
                REGISTER pix1 AS LONG
                REGISTER y AS LONG
                
                Storm$="c:\starlings2.bmp"
                
                
                'get the size of the bitmap
                nFile& = FREEFILE
                OPEN Storm$ FOR BINARY AS nFile&
                GET #nFile&, 19, nWidth&
                GET #nFile&, 23, nHeight&
                CLOSE nFile&
                
                'load the bitmap of the storm system
                GRAPHIC BITMAP LOAD Storm$,nWidth&,nHeight&,%BLACKONWHITE TO hBmp1???
                
                GRAPHIC ATTACH hBmp1???,0
                GRAPHIC GET BITS TO Image1$
                
                xsize& = CVL(image1$,1)
                ysize& = CVL(image1$,5)
                
                'show it on screen so I can see the effect of each stage of processing
                GRAPHIC WINDOW "Storm ID",1,1,xsize&,ysize& TO hWin1???
                GRAPHIC ATTACH hWin1???,0 ,REDRAW
                
                GRAPHIC COPY hBmp1???,0
                
                DIM bmp(xsize&-1,ysize&-1) AS LONG AT STRPTR(Image1$)+8
                
                PRINT xsize&,ysize&
                PRINT LEN(image1$)
                
                GRAPHIC REDRAW
                
                CONSOLE SET LOC 800,0
                CONSOLE SET FOCUS
                
                
                PRINT "Original image"
                WAITKEY$
                PRINT "Improving contrast"
                
                contrast##=0.95
                
                       
                'scan the image to find those points which are significantly darker than the points either side
                FOR x& = 1 TO xsize&-1-1
                    FOR y& = 0 TO ysize&-1
                        pix1&=bmp(x&,y&)
                        pix2&=bmp(x&-1,y&)
                        pix3&=bmp(x&+1,y&)
                
                        brightness1&= (pix1& AND 255) + ((pix1& AND &h0000ff00) \256 ) + ((pix1& AND &h00ff0000) \ 65536)
                        brightness2&= (pix2& AND 255) + ((pix2& AND &h0000ff00) \256 ) + ((pix2& AND &h00ff0000) \ 65536)
                        brightness3&= (pix3& AND 255) + ((pix3& AND &h0000ff00) \256 ) + ((pix3& AND &h00ff0000) \ 65536)
                
                        'if pix1 is darker than those either side, identify it as a possible bird
                        IF ((brightness2&/brightness1&) > contrast##) AND ((brightness3&/brightness1&) > contrast&) THEN
                             GRAPHIC SET PIXEL (x&,y&),%BLACK
                        ELSE
                             GRAPHIC SET PIXEL (x&,y&),%WHITE
                        END IF
                
                
                    NEXT
                #IF %DEF (%showscreenupdate)
                    GRAPHIC REDRAW
                #ENDIF
                
                NEXT
                
                'copy new image back to array
                GRAPHIC GET BITS TO Image1$
                REDIM bmp(xsize&-1,ysize&-1) AS LONG AT STRPTR(Image1$)+8
                           
                
                
                PRINT "Identifying individual starlings"
                'identify each system from the others
                NextColour&=1
                DIM systemlocationx(100000) AS LONG
                DIM systemlocationy(100000) AS LONG
                
                FOR x& = 0 TO xsize&-1
                    FOR y& = 0 TO ysize&-1
                        GRAPHIC GET PIXEL (x&,y&) TO pix1&
                        IF pix1& = %WHITE THEN
                            GRAPHIC PAINT (x&,y&),NextColour&,%BLACK
                            systemlocationx(NextColour&)=x&
                            systemlocationy(NextColour&)=y&
                
                            NextColour&=NextColour&+1
                        END IF
                    NEXT
                
                #IF %DEF (%showscreenupdate)
                    GRAPHIC REDRAW
                #ENDIF
                
                NEXT
                GRAPHIC REDRAW
                
                PRINT NextColour&-1;"Starlings found"
                WAITKEY$
                
                'colour them all white so they can be seen on the final picture
                FOR x& = 0 TO xsize&-1
                    FOR y& = 0 TO ysize&-1
                        GRAPHIC GET PIXEL (x&,y&) TO pix1&
                        IF pix1& <> %BLACK THEN
                            GRAPHIC SET PIXEL (x&,y&),%WHITE
                
                         END IF
                    NEXT
                NEXT
                GRAPHIC REDRAW
                
                WAITKEY$
                
                GRAPHIC SAVE "c:\starlingoutput.bmp"
                
                END FUNCTION
                Last edited by Paul Dixon; 26 Dec 2008, 10:54 AM.

                Comment


                • #9
                  Originally posted by Eric Pearson View Post
                  Why not simply count the number of dark pixels in the picture, then divide by your best guess of pixels-per-bird?
                  Eric, that is a reasonable approach on an image-at-a-time basis. Pixels per bird brings in yet another variable, the distance between the camera and the flock. What I am hoping to work out is how to distinguish an irregular shape from its background. I'm sure that this has many applications and people are doing it all the time in process control, crop measurement, security, military applications. I would just like to join that club, even as a very junior member!

                  Comment


                  • #10
                    FWIW & AFAIK the biggest application of this is cell counting in medical applications. Google "cell counting" and software to get a good overview of what's out there. Hopefully there will be some papers that show how they go about it.

                    Comment


                    • #11
                      Originally posted by Chris Holbrook View Post
                      Gösta, Thanks for the BW copy - how did you make it?
                      Paint Brush Pro (a PhotoShp type program) has a BW option.

                      What I was going to do (haven't started yet) was look at 5x5 (or 4x or 3x) blocks of pixels and if any were not zero), count it as a bird. In BW, it should be pretty easy. In color, much harder.

                      i{later} Finished. I came up with 3,110 Birds in 12,065 Blocks.

                      Building on Paul's code'
                      Code:
                       'PBWIN 9.00 - WinApi 05/2008 - XP Pro SP3
                      'http://www.powerbasic.com/support/pbforums/showthread.php?t=39425
                      'Original code by Paul Dixon
                      #Register All ' suggestion by Theo G. faster running?
                      '#Dim All                             
                      #Include "WIN32API.INC"
                      Macro wate
                        Graphic ReDraw
                        Graphic WAITKEY$
                      End Macro
                      '
                      Function PBMain
                        Local Image1, Pic As String 
                        Local Margin, ctr, ctr1, ctr2, ctr3, hctr, wctr, Bird_Count, Bird_Size, xWidth, xHeight, nWidth, nHeight, nfile As Long
                        Local Block_Size, Blocks_Total As Long
                        Local hBmp1, hWin1 As Dword
                      '  
                       Pic$ = "starlings_BW.bmp"
                       nfile = FreeFile
                      '
                      Open Pic$ For Binary As nFile& 'get size of bitmap
                      Get #nFile&, 19, nWidth 'width begins at 19th byte
                      Get #nFile&, 23, nHeight 'Height begibsa at 23rd byte
                      Close nFile&
                      '
                      'load the bitmap 
                      Graphic Bitmap Load Pic$, nWidth&, nHeight& To hBmp1 'assign the bitmap to a handle (DC?)
                      '
                      Graphic Attach hBmp1, 0 'assign a target for future graphic satements
                      Graphic Get Bits To Image1$ 'put the bmp ito a string
                      '
                      xWidth = Cvl(image1$,1) 'width is first 4 bytes (long)
                      xHeight = Cvl(image1$,5) 'Height is next four
                      '
                      'show it on screen so I can see the effect of each stage of processing
                      Graphic Window "Starlings", 1, 1, xWidth, xHeight To hWin1 'assign to a window handle
                      Graphic Attach hWin1, 0, ReDraw 'assign a target for future graphic satements
                      '
                      Graphic Copy hBmp1???,0 'copy Pic$ to "Starlings" window created above
                      '
                      Dim bmp(1 To xWidth, 1 To xHeight) As Long At StrPtr(Image1$) + 8 'create a working array
                      '
                      '
                      'no birds should be bigger than Bird_Size
                        Bird_Size = 5
                        Margin = 3 'Bird_Size \ 2
                        Reset Bird_Count            
                        Block_Size = Bird_Size * Bird_Size 
                      '  
                                'start down a little   'stop up a little
                         For hctr = Margin   To xHeight - Margin  Step Bird_Size
                           For wctr = Margin To xWidth - Margin Step Bird_Size 
                               Incr Blocks_Total
                               'now see if any filled
                               Reset ctr
                               For ctr1 = -2 To 2
                                 For ctr2 = -2 To 2
                                    If bmp(wctr + ctr2, hctr + ctr1) < 1 Then Incr ctr '> 0 is black color
                                 Next ctr2
                               Next ctr1
                      '         
                               If ctr > 0 And ctr < Block_Size Then ' Case of block being all black
                                  Incr Bird_Count
                               End If   
                           Next wctr
                         Next hctr
                      '
                      '   
                      '
                      Graphic ReDraw
                      '
                        wate
                      '
                         Open "Check.txt" For Output As #nfile
                         Print #nfile, Using$("#, Wide  #, High", xwidth, xHeight)   
                         Print #nfile, Using$("#, Birds in #, Blocks ", Bird_Count, Blocks_Total)
                      '                                                                       
                         For hctr = 1 To xHeight        
                          Print #nfile, Using$("#,#### ", hctr);
                           For wctr = 1 To 10 'just to see how it looks
                             Print #nfile, Using$("#, ", bmp(wctr, hctr));
                           Next wctr
                           Print #nfile, " "
                         Next hctr
                         Close
                      End Function
                      '
                      In file
                      640 Wide 480 High
                      3,110 Birds in 12,065 Blocks
                      ...
                      While probably not an accurate count, I'd bet it's pretty close.
                      Last edited by Gösta H. Lovgren-2; 26 Dec 2008, 04:23 PM. Reason: clarity?
                      It's a pretty day. I hope you enjoy it.

                      Gösta

                      JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                      LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                      Comment


                      • #12
                        Gösta's tip re grey scale is the way to go with this image but I reckon you've been a bit heavy on the contrast peddle, Gösta.

                        I've used less contrast on the whole image then applied selective contrast to the lower part. Paint Shop Pro has an Edge Effect and the Trace Contour works a treat on the image so far giving a higher retention of them thar birds.



                        I tried your code Gösta but it GPF'd and I haven't had time to check why.

                        Comment


                        • #13
                          Originally posted by David Roberts View Post
                          Gösta's tip re grey scale is the way to go with this image but I reckon you've been a bit heavy on the contrast peddle, Gösta.
                          A heavy foot has been a problem for me all my life {sigh}.
                          I've used less contrast on the whole image then applied selective contrast to the lower part. Paint Shop Pro has an Edge Effect and the Trace Contour works a treat on the image so far giving a higher retention of them thar birds.
                          I have no idea how to do that. Used PBP since it was version 1 and shareware. Just kept updating as each version came to support the original author (forget his name) who gave great support. I should have stopped around version 4 or 5 (my last is 8.xx) because then it started becoming more and more complex for the (very) casual user. {oh well}.
                          I tried your code Gösta but it GPF'd and I haven't had time to check why.
                          It runs fine here (picture should be in same folder as program). You may have to put in "Drve:\Folder\Starlings..." if you have it elsewhere (though I don't think that would cause a GPF).

                          ===================================
                          "The gods too are fond of a joke."
                          Aristotle (384-322 B.C.)
                          ===================================
                          It's a pretty day. I hope you enjoy it.

                          Gösta

                          JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                          LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                          Comment


                          • #14
                            Black & White estimate
                            3,110 Birds in 12,065 Blocks of 5 square
                            Color Total = 4,819,473,112,545 Color Avg = 15,688,389

                            Color Estimate at 16,777,215 for a sky color
                            3,078 Birds in 3,078 Pixels (at 1 Px per bird) 1% of total

                            Grey Estimate at 16,777,215 for a sky color
                            3,078 Birds in 8,839 Pixels (at 1 Px per bird) 3% of total

                            '*****************

                            My best guess is there's about 3,088.666666666666666667 birds in the picture {grin}.


                            '
                            Code:
                             'PBWIN 9.00 - WinApi 05/2008 - XP Pro SP3
                            'http://www.powerbasic.com/support/pbforums/showthread.php?t=39425
                            'Original code by Paul Dixon
                            #Register All ' suggestion by Theo G. faster running?
                            '#Dim All                             
                            #Include "WIN32API.INC"
                            Macro wate
                              Graphic ReDraw
                              Graphic WAITKEY$
                            End Macro
                            '
                            Macro pf = Print #nfile, 
                            '
                            Macro Load_Picture
                              Open Pic$ For Binary As nFile& 'get size of bitmap
                              Get #nFile&, 19, nWidth 'width begins at 19th byte
                              Get #nFile&, 23, nHeight 'Height begibsa at 23rd byte
                              Close nFile&
                              '
                              'load the bitmap 
                              Graphic Bitmap Load Pic$, nWidth&, nHeight& To hBmp1 'assign the bitmap to a handle (DC?)
                              '
                              Graphic Attach hBmp1, 0 'assign a target for future graphic satements
                              '
                              Graphic Get Bits To Image1$ 'put the bmp ito a string
                              '
                              xWidth = Cvl(image1$,1) 'width is first 4 bytes (long)
                              xHeight = Cvl(image1$,5) 'Height is next four
                              '
                              'show it on screen so I can see the effect of each stage of processing
                              Graphic Window "Starlings", 1, 1, xWidth, xHeight To hWin1 'assign to a window handle
                              Graphic Attach hWin1, 0, ReDraw 'assign a target for future graphic satements
                              '
                              Graphic Copy hBmp1,0 'copy Pic$ to "Starlings" window created above
                              '
                              ReDim bmp(1 To xWidth, 1 To xHeight) As Long At StrPtr(Image1$) + 8 'create a working array
                              ReDim Colrs(1 To xWidth * xHeight) 'put color values in
                              '
                              Graphic ReDraw
                              wate
                            End Macro
                            '
                            Function PBMain
                              Local Margin, ctr, ctr1, ctr2, ctr3, hctr, wctr, Bird_Count, Bird_Size, xWidth, xHeight, nWidth, nHeight, nfile As Long
                              Local Bird_Pixels_DR, Pixels_Total, Bird_Pixels, Bird_Color, Color_Avg, Colrs(), Block_Size, Blocks_Total As Long
                              Local Image1, Pic As String 
                              Local hBmp1, hWin1 As Dword
                              Local Color_Ttl As Quad
                            '  
                             Pic$ = "starlings_BW.bmp"
                             nfile = FreeFile 
                            '
                               Load_Picture
                            '
                             
                               For hctr = 1 To xheight
                                 For wctr = 1 To xWidth     
                                   Colrs(xWidth * xHeight) = bmp(wctr, hctr)
                                   Color_Ttl = Color_Ttl + bmp(wctr, hctr)
                                 Next wctr
                               Next hctr                                   
                            '                                               
                              Color_Avg = Color_Ttl \ (xWidth * xHeight)
                            '
                            'no birds should be bigger than Bird_Size
                              Bird_Size = 5
                              Margin = 3 'Bird_Size \ 2
                              Reset Bird_Count            
                              Block_Size = Bird_Size * Bird_Size 
                            '
                            ' Any color within a Bird_Size Block = a bird 
                                      'start down a little   'stop up a little
                               For hctr = Margin   To xHeight - Margin  Step Bird_Size
                                 For wctr = Margin To xWidth - Margin Step Bird_Size 
                                     Incr Blocks_Total
                                     'now see if any filled
                                     Reset ctr
                                     For ctr1 = -2 To 2
                                       For ctr2 = -2 To 2
                                          If bmp(wctr + ctr2, hctr + ctr1) < 1 Then Incr ctr
                                       Next ctr2
                                     Next ctr1
                            '         
                                     If ctr > 0 And ctr < Block_Size Then ' Case of block being all black
                                        Incr Bird_Count
                                     End If   
                                 Next wctr
                               Next hctr
                            '
                            '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                            '<<< Now do it in color
                            '
                            '   
                               Bird_Color = RGB(90, 100, 100) 'picked from photo as darkest sky color
                                                               'Anything darker (lower number) is considered a part of a bird  
                             Pic$ = "starlings.bmp"
                             nfile = FreeFile 
                               Load_Picture
                             
                             
                               For hctr = 1 To xHeight
                                 For wctr = 1 To xWidth
                                     Incr Pixels_Total
                                     'now see if any filled
                                      If bmp(wctr, hctr) <  Bird_Color Then Incr Bird_Pixels
                                 Next wctr
                               Next hctr
                            '
                            '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                            '<<< Now do it in DR's contrasted
                            '
                            '   
                               Bird_Color = RGB(255, 255, 255) 'White
                                                               'Anything darker (lower number) is considered a part of a bird  
                             Pic$ = "starlingsDR.bmp"
                             nfile = FreeFile 
                               Load_Picture
                             
                             
                               For hctr = 1 To xHeight
                                 For wctr = 1 To xWidth
                                     'now see if any filled
                                      If bmp(wctr, hctr) <  Bird_Color Then Incr Bird_Pixels_DR
                                 Next wctr
                               Next hctr
                            '
                            '
                            '
                              wate
                            '
                               Open "Check.txt" For Output As #nfile
                               Print #nfile, Using$("#, Wide  #, High = #, Total = #,  #,", xwidth, xHeight, xwidth * xHeight, Pixels_Total)   
                               Print #nfile, ,"Black & White estimate"
                               Print #nfile, Using$("#, Birds in #, Blocks of 5 square", Bird_Count, Blocks_Total)
                               Print #nfile, Using$("Color Total = #,  Color Avg = #,", Color_Ttl, Color_Avg)
                               ctr = 1
                               pf " "                                                                    
                               pf Using$("Color Estimate at #, for a sky color", Bird_Color)
                               pf Using$("#, Birds in #, Pixels (at # Px per bird) #% of total", _
                                          Bird_Pixels \ ctr, Bird_Pixels, ctr,  Bird_Pixels / Pixels_Total * 100)
                             
                               ctr = 1
                               pf " "                                                                    
                               pf Using$("Grey Estimate at #, for a sky color", Bird_Color)
                               pf Using$("#, Birds in #, Pixels (at # Px per bird) #% of total", _
                                          Bird_Pixels \ ctr, Bird_Pixels_DR, ctr,  Bird_Pixels_DR / Pixels_Total * 100)
                             
                               Close
                            End Function
                            '
                            =====================================================
                            "Without accepting the fact that everything changes,
                            we cannot find perfect composure.
                            But unfortunately, although it is true,
                            it is difficult for us to accept it.
                            Because we cannot accept
                            the truth of transience,
                            we suffer."
                            Shunryu Suzuki
                            =====================================================
                            Last edited by Gösta H. Lovgren-2; 27 Dec 2008, 12:09 AM. Reason: Added the grey scale
                            It's a pretty day. I hope you enjoy it.

                            Gösta

                            JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                            LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                            Comment


                            • #15
                              Originally posted by Gösta H. Lovgren-2 View Post
                              My best guess is there's about 3,088.666666666666666667 birds in the picture {grin}.
                              That is the equivalent of 3,085 starlings, one seagull and a brace of sparrows.

                              I am profoundly impressed.

                              Comment


                              • #16
                                Originally posted by Chris Holbrook View Post
                                That is the equivalent of 3,085 starlings, one seagull and a brace of sparrows.

                                I am profoundly impressed.
                                Why? That I caught the sparrows?

                                Actually Paul's code showing how to put a graphic into an array:

                                Graphic Get Bits ...
                                ReDim bmp(1 To xWidth, 1 To xHeight) As Long At StrPtr(Image1$) + 8 ...

                                made it absurdly easy, which is not to say accurate. Actually I think the two sparrows may be seagull turds (they are so small details are hird to make out.)

                                ===========================================
                                "A pint of sweat saves a gallon of blood."
                                General George S. Patton (1885-1945)
                                ===========================================
                                It's a pretty day. I hope you enjoy it.

                                Gösta

                                JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                                LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                                Comment


                                • #17
                                  Quote:
                                  Originally Posted by Gösta H. Lovgren-2
                                  My best guess is there's about 3,088.666666666666666667 birds in the picture {grin}.

                                  That is the equivalent of 3,085 starlings, one seagull and a brace of sparrows.

                                  I am profoundly impressed.
                                  All together now....

                                  ....Annnnd a partridge in a pear treeeeeee!!!!!



                                  Seriously though I think the problem is more a context of color range vs the pixel being looked at to determine results
                                  Engineer's Motto: If it aint broke take it apart and fix it

                                  "If at 1st you don't succeed... call it version 1.0"

                                  "Half of Programming is coding"....."The other 90% is DEBUGGING"

                                  "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                                  Comment


                                  • #18
                                    Originally posted by Cliff Nichols View Post
                                    Seriously though I think the problem is more a context of color range vs the pixel being looked at to determine results
                                    Yes. If you were to use such a technique in "production", you might have to use different strategies to maximise the number of objects discerned, assuming that the birds are smaller than cloud features.Geese against a "mackerel sky" would be challenging.

                                    Comment


                                    • #19
                                      Originally posted by Chris Holbrook View Post
                                      Yes. If you were to use such a technique in "production", you might have to use different strategies to maximise the number of objects discerned, assuming that the birds are smaller than cloud features.Geese against a "mackerel sky" would be challenging.
                                      Assuming the picture was in color, It seems geese would be easier and more accurate in some respects, if one could find a color unique to the geese (say a green or red or brown). Then one could just search for that particular color (grouping). In the first run I examine blocks of 25. If one were searching for Red, then any reds in the block would be a (1) goose.

                                      What made this particular exercise rewarding for me was the technique Paul showed (putting the image into an array of pixel colors). Quite clever really for one unfamilar with graphics work. (me that is, not Paul)

                                      At any rate, here's the colors for a 21H x 11W section which looks like it has 6 of the smaller (fainter) birds.

                                      Code:
                                       
                                      section.bmp
                                        1  8,754,606  8,688,813  8,754,093  8,688,300  8,688,300  8,688,300  8,819,372  8,885,165  8,885,165  8,885,165  8,885,165 
                                        2  8,885,163  8,885,163  8,754,347  8,688,554  8,688,300  8,688,300  8,688,300  8,688,300  8,819,372  8,885,165  8,884,650 
                                        3  8,819,370  8,819,370  8,688,554  8,688,554  8,688,554  8,688,554  8,688,300  8,688,300  8,819,372  8,885,165  8,884,650 
                                        4  8,819,370  8,819,370  8,754,347  8,688,554  8,688,554  8,688,554  8,688,300  8,688,300  8,885,165  8,885,165  8,950,445 
                                        5  8,885,163  8,885,163  8,885,163  8,885,163  8,885,163  8,885,163  8,819,372  8,885,165  8,885,165  8,885,165  8,885,165 
                                        6  8,885,163  8,885,163  8,885,163  8,885,163  8,885,163  8,885,163  8,819,372  8,885,165  8,885,165  8,819,372  8,819,372 
                                        7  8,885,163  8,885,163  8,950,956  8,885,163  8,885,163  8,885,163  8,819,372  8,885,165  8,885,165  8,819,372  8,819,372 
                                        8  8,885,165  8,885,165  8,950,956  8,885,163  8,819,370  8,819,370  8,819,372  8,885,165  8,885,165  8,819,372  8,819,372 
                                        9  8,885,165  8,950,958  8,950,956  8,885,163  8,819,370  8,819,370  8,885,163  8,885,163  8,885,165  8,819,372  8,885,165 
                                       10  9,016,749  8,885,163  9,016,490  8,884,904  8,950,443  8,950,443  8,950,445  8,950,445  9,016,238  8,950,445  8,885,165 
                                       11  9,082,542  8,753,577  8,490,146  8,161,181  8,621,478  9,082,029  9,082,031  9,016,238  9,016,238  8,950,445  8,819,372 
                                       12  9,082,542  8,819,370  8,424,099  7,502,997  7,371,411  7,568,790  8,753,066  8,950,445  9,016,238  9,016,238  9,016,238 
                                       13  8,885,163  9,016,749  9,148,335  8,753,577  8,818,857  8,950,443  8,884,652  8,950,445  8,818,859  8,884,652  9,082,031 
                                       14  9,016,749  8,885,163  8,950,956  8,819,370  9,016,749  9,148,335  8,885,165  8,621,993  8,029,343  8,226,722  8,884,652 
                                       15  9,148,335  8,950,956  9,016,749  8,885,163  8,950,956  8,819,370  8,753,579  8,687,786  8,029,856  8,227,235  8,884,652 
                                       16  9,082,029  8,884,650  8,950,956  8,950,956  9,082,542  8,885,163  9,016,751  9,148,337  8,555,945  8,687,531  9,147,824 
                                       17  9,147,822  9,016,236  9,016,749  8,885,163  8,950,956  8,950,956  8,687,786  8,621,993  7,898,015  8,292,773  9,082,031 
                                       18  8,950,958  8,885,165  9,016,751  8,950,958  8,819,372  8,950,958  8,885,165  8,819,372  7,964,063  8,490,407  9,147,569 
                                       19  8,950,958  8,885,165  9,016,751  8,950,958  8,885,165  9,016,751  8,885,165  9,082,544  8,687,786  8,950,958  9,147,824 
                                       20  9,016,238  9,016,238  9,082,544  9,016,751  8,950,958  9,016,751  8,885,165  9,082,544  9,082,544  9,082,544  9,016,751 
                                       21  9,016,496  9,082,289  9,082,544  8,950,958  8,950,958  9,016,751  9,016,751  8,950,958  9,016,751  9,016,751  8,950,958
                                      The .bmp is attached and here is what it looks like blown up 300 times:
                                      http://www.SwedesDock.com/powerbasic/section21x11.bmp (size exceeds forum upload limit)

                                      Just kinda neat.

                                      ======================================================
                                      "How can I lose to such an idiot?"
                                      A shout from chessmaster Aaron Nimzovich (1886-1935)
                                      ======================================================

                                      Oh, just for the record, I made no claims as to the accuracy of the number of birds, only "My best guess is there's about 3,088.666666666666666667 birds in the picture {grin}."
                                      Attached Files
                                      Last edited by Gösta H. Lovgren-2; 27 Dec 2008, 09:40 PM. Reason: For the posterior record (as in posterity)
                                      It's a pretty day. I hope you enjoy it.

                                      Gösta

                                      JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                                      LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                                      Comment


                                      • #20
                                        Gösta,
                                        if one could find a color unique to the geese
                                        It's not that simple
                                        First, if a bird almost fills a single pixel then that pixel will be a dark shade of bird but if that same bird is half way between 2 pixels then each pixel will be a mix of the background colour and the bird so the colour of the pixel no longer identifies that there is a bird there. It might be different if the picture was a close up of the birds where each bird occupied many pixels so some pixels were always full of bird.

                                        Second, the images are JPGs. If you look at your zoomed in shot you can see lots of artifacts introduced by the JPG compression. These show up as patches of varying light and dark pixels around each bird. The APPARENT colour to a person might be a reasonable match for the real image but to a computer these colours are just noise and crude approximations to the real colour in the scene and don't match at all. This is the reason my simple method earlier of checking the brightness each side of a pixel didn't work, it identified the JPG artifacts as changes in colour so thought they were birds.

                                        I think you're on the right lines to zoom in and take a look at what a computer sees when it looks at the image pixel by pixel. You just need to come up with the algoritm that the computer needs to correctly identify bird from noise. Colour alone is never going to work, you need to look at the difference in colour between pixels in small areas of the image.


                                        Paul.

                                        Comment

                                        Working...
                                        X