Welcome Guest! You need to login or register to make posts.

Notification

Icon
Error

Options
Go to last post Go to first unread
Raghavendra Mudugal  
#1 Posted : Sunday, March 27, 2005 2:46:00 PM(UTC)
Raghavendra Mudugal

Rank: Member

Groups: Member
Joined: 3/27/2005(UTC)
Posts: 16

Hello, :)

I have loaded a image of houes loaded in the control. Now i need to know how to select the portion of the image (user defined shape, like polygon style) and change the color of the selected part. Say for example , in house image, I select the roof in different shape and
change the color to red.

Hope to see the answers at your earliest

Many Thanks
With Regards,
Raghavendra Mudugal
Andrew  
#2 Posted : Sunday, April 10, 2005 3:46:00 PM(UTC)
Andrew

Rank: Advanced Member

Groups: Member, Administration
Joined: 8/2/2003(UTC)
Posts: 876

Thanks: 2 times
Was thanked: 27 time(s) in 27 post(s)
Hi Raghavendra,

According to our email correspondence, the only problem you need to solve is to draw rubberband polygon at the BitmapViewer control. I have written a code sample for this at last weekends. Please find it below.

I have tried to comment it in details. But if anything is still unclear here, please post a message here.

Code:
Option Base 0

' A Graphics object which draws the polygon
Private objGraphics As Graphics

' An array of points which represents the polygon
Private arrPolygon() As Long

' A number of point which is currently being dragged. If no current point selected, it equals to the NotInitialized
Private currentPoint As Long

' A value which specifies an "epsilon neighborhood" of the anchor point (i.e. the distance around the point
' which is considered as this point when hit test is applied)
Const Epsilon As Long = 6

' A value which specifies that the numeric value is not initialized (e.g. the index of the
' current point when no point selected). It should be negative (invalid) so that it would
' not be confused with valid values.
Const NotInitialized = -100

Private Sub DrawPolygon()

    ' Since our polygon is stored in coordinates relatively the image, we need to recalculate these coordinates
    ' relatively the BitmapViewer control.
    Dim tempPolygon() As Long
    ReDim tempPolygon(UBound(arrPolygon))
    For I = 0 To UBound(arrPolygon) Step 2
        tempPolygon(I) = BitmapViewer1.BitmapToControlXCoord(arrPolygon(I))
        tempPolygon(I + 1) = BitmapViewer1.BitmapToControlYCoord(arrPolygon(I + 1))
    Next I


    ' Polygon requires at least four points, that's why if user clicked less points, skip this line.
    If UBound(tempPolygon) - LBound(tempPolygon) + 1 >= 8 Then
        ' Set drawing settings for the polygon
        objGraphics.Brush.PrimaryColor = ColorBlack
        objGraphics.Brush.IsBackgroundTransparent = True
        objGraphics.Brush.Type = BrushTypeHatch
        objGraphics.Brush.HatchStyle = HatchStyleBackwardDiagonal
        
        ' Draw a filled and outlined polygon
        objGraphics.DrawPolygon tempPolygon, True, True
    End If

    ' Draw anchor points
    For I = LBound(tempPolygon) To UBound(tempPolygon) Step 2
        ' Set drawing settins for the anchor point.
        objGraphics.Brush.PrimaryColor = ColorRed
        objGraphics.Brush.Type = BrushTypeSolid
        
        ' Draw an anchor point
        objGraphics.DrawRectangle tempPolygon(I) - Epsilon / 2, tempPolygon(I + 1) - Epsilon / 2, Epsilon, Epsilon, True
    Next
    
End Sub

' This function tests whether a point with specified coordinates is already
' placed to the polygon. If yes, it returns the index of this point (i.e. the index
' of X coordinate of this point). Otherwise NotInitialized value is used.
Private Function HitTest(x As Long, y As Long) As Long
    For I = LBound(arrPolygon) To UBound(arrPolygon) Step 2
    
        ' Since it is very hard to hit the exact pixel which specifies the coordinate
        ' of the polygon vertex, we define an "epsilon neighborhood" for this point.
        ' In other words if the selected coordinates will be as close to this point as
        ' a number of pixels specified as Epsilon, the function will say "OK".
        If Abs(arrPolygon(I) - x) < Epsilon And Abs(arrPolygon(I + 1) - y) < Epsilon Then
            HitTest = I
            Exit Function

        End If
    Next
    
    ' Not found
    HitTest = NotInitialized
End Function

Private Sub BitmapViewer1_DoubleBufferPaint(ByVal Hdc As stdole.OLE_HANDLE)
    If UBound(arrPolygon) > 0 Then
        objGraphics.Hdc = Hdc
        DrawPolygon
    End If
End Sub

Private Sub BitmapViewer1_ImageMouseDown(ByVal button As Long, ByVal shift As Long, ByVal x As Long, ByVal y As Long)
    
    ' Determine if some point has been selected.
    currentPoint = HitTest(x, y)
    
    ' If not, it means that the user wants to add new one.
    If currentPoint = NotInitialized Then
        
        ' A number of elements in the arrPolygon array. The number of points is count/2.
        Dim count As Long
        count = UBound(arrPolygon) - LBound(arrPolygon) + 1
        
        ' I did not find an easy way to handle the situation when no elements are available
        ' in array. That's why I had to do a trick - in Form_Load I create a single point and
        ' set their coordinates to NotInitialized. When the user add the first point, I just
        ' rewrite these coordinates, and next points are added in a common way (using Redim statement).
        If count = 2 And arrPolygon(0) = NotInitialized And arrPolygon(1) = NotInitialized Then
            arrPolygon(0) = x
            arrPolygon(1) = y
        Else
            ReDim Preserve arrPolygon(count + 1)
            arrPolygon(count) = x
            arrPolygon(count + 1) = y
        End If
        
        ' Redraw the polygon at the control.
        BitmapViewer1.FastRefresh
    End If
End Sub

Private Sub BitmapViewer1_ImageMouseMove(ByVal button As Long, ByVal shift As Long, ByVal x As Long, ByVal y As Long)
    
    ' If the current point is selected, move this point.
    If currentPoint <> NotInitialized Then
        arrPolygon(currentPoint) = x
        arrPolygon(currentPoint + 1) = y
        BitmapViewer1.FastRefresh
    End If
    
    ' Display current coordinates
    Label1.Caption = "X :" & x & " Y: " & y
End Sub

Private Sub BitmapViewer1_ImageMouseUp(ByVal button As Long, ByVal shift As Long, ByVal x As Long, ByVal y As Long)
    
    ' When the mouse button is released, we need to "detach" from the current point.
    currentPoint = NotInitialized
End Sub

' Initialization is made there.
Private Sub Form_Load()

    ' Here you can load the bitmap from file, etc. I am just creating 640x480 image for brevity.
    BitmapViewer1.Bitmap.CreateNew 640, 480
    
    ' Create and initialize a Graphics object. Note, I am using GDI engine (rather than GDI+)
    ' to provide higher performance. But if you want to draw semitransparent polygon, etc., you
    ' should use GDI+.
    Set objGraphics = New Graphics
    objGraphics.Engine = DrawingEngineGdi
    
    ' Initialize polygon. See comments in BitmapViewer1_ImageMouseDown function
    ' for more details.
    ReDim arrPolygon(1)
    arrPolygon(0) = NotInitialized
    arrPolygon(1) = NotInitialized
    
    ' No current point selected.
    currentPoint = NotInitialized
End Sub

Edited by user Monday, December 24, 2007 3:55:35 PM(UTC)  | Reason: Not specified

Raghavendra Mudugal  
#3 Posted : Sunday, April 10, 2005 6:18:00 PM(UTC)
Raghavendra Mudugal

Rank: Member

Groups: Member
Joined: 3/27/2005(UTC)
Posts: 16

Hello Andrew

I have copied the code and I am working on it. Its really a worthy example. But I have
something to say.

I saw the code, and while making the selection on the image loaded, you are drawing the
polygon and rectangle on the captured point of the mouse events. And these drawn lines
are permanent of the image loaded. If I want to make a selection on the other region.
I still see those line (previously selected region) covered with that. If you make a selection
of Square or rectangle by setting the mouse_mode to ED_SELECT, there you can see that
if I select one region and change the color and select the other region for changing the color
those dashed red lines will dissappear automatically.

Is there anything such way we can do with the polygon selection. I have already done this
before but no the way you did, actually i stored the points of x and y in the array of every
click and was drawling the line from previous points clicked to new points clicked, so user
comes to know the region selected. But these lines are permanent. If I save the image to the
disk it is saved along with the lines. So same as yours (i guess).

I need a polygon selection area which also dissappear on the new selection. In this job we
reached 50% of the work but main thing is i need this to work like ED_SELECT but its should
be automatic dissappear on new region selection.

Hope i made you clear with the thought that i have. Anything else please reply to this at your
earliest, and thank you so much for the code. its really great.

With Regards,
Raghavendra Mudugal
Andrew  
#4 Posted : Sunday, April 10, 2005 10:01:00 PM(UTC)
Andrew

Rank: Advanced Member

Groups: Member, Administration
Joined: 8/2/2003(UTC)
Posts: 876

Thanks: 2 times
Was thanked: 27 time(s) in 27 post(s)
This polygon is not drawn at the source image. It is drawn at the control (in the same way as a rectangle selection). That's why when you will discard the selection, these lines will disappear.

If you need to discard the selection, you should just remove all elements from arrPolygon variable and re-initialize it in the following way:

Code:
    ' Initialize polygon. See comments in BitmapViewer1_ImageMouseDown function
    ' for more details.
    ReDim arrPolygon(1)
    arrPolygon(0) = NotInitialized
    arrPolygon(1) = NotInitialized


You may notice that the same code is used in Form_Load event handler.

This selection is not disappeared automatically, because I do not quite understand when to do it. When the user works with the rectangular selection, the software can interpret beginning of new selection when the user clicks and drags the mouse. It is wrong in case of polygon. If the user clicks the control, he either add new vertex, or capture the previously added vertex and move it. He does not create new selection with mouse, he just modifies the existing one.

So I think you should clear the selection in two cases:
  1. When the special "Clear Selection" button is clicked.
  2. When the recoloring is applied.


You see it is easy to implement both of these cases by using the code above.

P.S. By the way, I have found out that I posted a bit incomplete code sample (DrawPolygon function - it was working incorrectly when the image scrolled). I have finished it and updated the code sample in this post. So please update it in your code.

Edited by user Monday, December 24, 2007 3:56:01 PM(UTC)  | Reason: Not specified

Raghavendra Mudugal  
#5 Posted : Tuesday, April 12, 2005 1:42:00 PM(UTC)
Raghavendra Mudugal

Rank: Member

Groups: Member
Joined: 3/27/2005(UTC)
Posts: 16

Hello Andrew :)

I got the example with new changes and its really working great. I just wanted to know
that you mentioned, those lines are drawn on the control and not on the image. I went
through the code but i did'nt get any idea how its drawn on the control. Could you please
explain this how actually its done.

Thank You
With Regards,
Raghavendra Mudugal
Andrew  
#6 Posted : Tuesday, April 12, 2005 10:23:00 PM(UTC)
Andrew

Rank: Advanced Member

Groups: Member, Administration
Joined: 8/2/2003(UTC)
Posts: 876

Thanks: 2 times
Was thanked: 27 time(s) in 27 post(s)
Hello Raghavendra,

It happens in the DoubleBufferPaint event. This event fires after the image from the "double buffer" is drawn at the control. It has a parameter HDC - handle to the device context of the BitmapViewer window. I just associate this HDC with the Graphics object, and every time I draw anything through the Graphics object, I draw it on the surface of the BitmapViewer window.

I hope it is cleaner now.
Raghavendra Mudugal  
#7 Posted : Wednesday, April 13, 2005 7:51:00 PM(UTC)
Raghavendra Mudugal

Rank: Member

Groups: Member
Joined: 3/27/2005(UTC)
Posts: 16

Hello Andrew :)

Yes, now its a lot clear. Even a kid can understand it very clearly. I have to change the code
here to draw on the control for polygon selection.

I will get you back if any i have to get clarified.

Thank you so much
With Regards,
Raghavendra Mudugal
Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.