none
bitmap to two dimensional array RRS feed

  • Question

  • So I have one connection to a camera but I am pulling data at multiple locations in the code. By data I mean the current frame.

    My plan is to display the 8 scale version on a (Aforge) videoSourcePlayer, so the user can zoom in and out and draw a box around the area they want, but then map that to a two dimensional array of 12 byte data.

    I am having a problem with the mapping,  somehow when I draw the box on the videoSourcePlayer  the corresponding pixels location are not the same in the two dimensional array and I am not sure why.

    Furthermore, when I  do a zoom in, the x and y values became negative numbers and I do not know how to map that back to my two dimensional array.

    now this code works for I do everything as a bitmap:

     private Bitmap Andrew()
            {
                Bitmap tempBitmap = new Bitmap(videoSourcePlayer.Width, videoSourcePlayer.Height);
                Graphics.FromImage(tempBitmap);
                Graphics g = Graphics.FromImage(tempBitmap);
                Bitmap originalBmp = videoSourcePlayer.GetCurrentVideoFrame();
              while (originalBmp == null)
                {
                    originalBmp = videoSourcePlayer.GetCurrentVideoFrame();
                }
                g.DrawImage(originalBmp, videoSourcePlayer.imagex, videoSourcePlayer.imagey, videoSourcePlayer.imgWidth, videoSourcePlayer.imgHeight);
    
                return tempBitmap;
            } 

    but when I try to do the two dimensional array my locations are off.

    and again I do not know how to handle the negative numbers when it comes to zoom in and out .

    here is my code :

     public double[,] GetSnapshot()
            {
                global_x = 0;
                global_y = 0;
                int rawImageSize = DetermineRawImageSize();
                byte[] temp = new byte[rawImageSize];
    
                float[] parameters = new float[1];
                parameters[0] = 1.5F;
                transfer.bits = new byte[getBufferSize()];
                FrameDescriptor frameDesc = new FrameDescriptor();
                //gets frame from camera
                ReturnCode rc = Api.GetNextFrame(m_hCamera, transfer.bits.Length, transfer.bits, ref frameDesc);
                int i4 = 0;
                int value2 = 0;
                global_y = (int)(videoSourcePlayer.imgHeight - videoSourcePlayer.imagey);
                global_x = (int)(videoSourcePlayer.imgWidth - videoSourcePlayer.imagex);
                double[,] returndata = new double[global_x, global_y];
    
                for (int x = (int)videoSourcePlayer.imagex; x < global_x; x++)
                {
                  for (int y = (int)videoSourcePlayer.imagey; y < global_y; y++ )
                    {
                        int value = ((transfer.bits[i4] << 8) + transfer.bits[i4 + 1]);
                        value2 = (value >> 4);
                        returndata[x,y]= value2;
                        i4 = i4 + 2;
                    }
                }
                return returndata;
            }

    can someone help me

    Wednesday, July 24, 2019 3:46 PM

All replies

  • You need to be careful with your terminology.  I don't know what you mean by "8 scale version", and when you say "12 byte data", I assume you mean "12-bit data".

    Why do you return an array of doubles?  The data are all small integers.

    You have your loops backwards.  The pixels in transfer.bits will arrive going across the row, and then down to the next row.  That means the outer loop has to be y, and the inner loop has to be x.

    You haven't shown us anything about zooming, so we aren't going to be able to comment on why you get negative coordinates.

    I don't understand what you're trying to do with global_x and global_y.  The image you get from GetNextFrame should have the entire bitmap, which is imgHeight and imgWidth. 


    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    Wednesday, July 24, 2019 9:37 PM
  • so the video player can only display 8 bits  pixel to the computer screen. from 0-255. I believe that is how the computer screen works. so the bitmap would not have a  pixel higher than 255. the camera gives me values from 0-4095 12 bits.

    I am using a two dimensional array  because  when the user draws a box on the videoplayer I am going to get the X and Y pixel coordinates and match that to the double array.

    what does this line do ?

      g.DrawImage(originalBmp, videoSourcePlayer.imagex, videoSourcePlayer.imagey, videoSourcePlayer.imgWidth, videoSourcePlayer.imgHeight);
    

    so when I zoom this is how zoom works :

    private void videoSourcePlayer_Click(object sender, EventArgs e)
            {
    
                MouseEventArgs arg = (MouseEventArgs)e;
                if (this.btZoomIn.Checked == true)
                {
                    this.videoSourcePlayer.Panflag = false;
                    float zoom = this.videoSourcePlayer.zoomFactor * 1.5F;
                    if (zoom > 10) zoom = 10F;     //maximum value is 10
                    //minimum value is 0.2
                    this.videoSourcePlayer.Zoom(zoom, arg.Location);
                   
                }
                else if (this.btZoomOut.Checked == true)
                {
                    this.videoSourcePlayer.Panflag = false;
                    float zoom = this.videoSourcePlayer.zoomFactor / 1.5F;
                    if (zoom < 1) zoom = 1F;     //minimum value is 0.2
                    this.videoSourcePlayer.Zoom(zoom, arg.Location);
                    
                }
    
    
                if (btPan.Checked == true)
                {
                    this.videoSourcePlayer.Pan(arg.Location);
                    this.videoSourcePlayer.Panflag = true;
                }
                videoSourcePlayer.RecalcImage = true;
            }
          

      // Paint control
            private void VideoSourcePlayer_Paint( object sender, PaintEventArgs e )
            {
                if ( !Visible )
                {
                    return;
                }
                // is it required to update control's size/position
                if ( ( needSizeUpdate ) || ( firstFrameNotProcessed ) )
                {
                    UpdatePosition( );
                    needSizeUpdate = false;
                }
    
                lock ( sync )
                {
                    Graphics  g = e.Graphics;
                    Rectangle rect = this.ClientRectangle;
                    Pen       borderPen = new Pen( borderColor, 1 );
                    int newWide = 0;
                    int newHeight = 0;
    
                    // draw rectangle
                    g.DrawRectangle( borderPen, rect.X, rect.Y, rect.Width - 1, rect.Height - 1 );
    
                    if ( videoSource != null )
                    {
                        if ( ( currentFrame != null ) && ( lastMessage == null ) )
                        {
                            imgWidth = (int)(this.Width * zoomFactor);
                            imgHeight = (int)(this.Height * zoomFactor);
                            if (RecalcImage && !Panflag)
                            {
                                imagex = (rect.Width < imgWidth) ? (zoomPosition.X * (-1) * (zoomFactor - 1)) : (rect.Width - imgWidth) / 2;
                                imagey = (rect.Height < imgHeight) ? (zoomPosition.Y * (-1) * (zoomFactor - 1)) : (rect.Height - imgHeight) / 2;
                                RecalcImage = false;
                            }
                            if (RecalcImage && Panflag == true && zoomFactor >1)
                            {
                                // x, y are positions of the upper left of the image
                                // PanPosition is the position of the cursor within the ClientRectangle
                                // need to find PanPosition relative to the image and move that point to the center of the ClientRectangle
    
                               
                                imagex -= (PanPosition.X - rect.Width / 2) ;
                                imagey -= (PanPosition.Y - rect.Height / 2) ;
                                if (imagex > 0)
                                    imagex = 0;
                                imagey = (imagey > 0) ? 0 : imagey;
    
                                if (imagex + imgWidth < rect.Width)
                                    imagex = rect.Width - imgWidth;
    
                                if (imagey + imgHeight < rect.Height)
                                    imagey = rect.Height - imgHeight;
    
                                
                                RecalcImage = false;
                            }
    
    
                            Bitmap frame = ( convertedFrame != null ) ? convertedFrame : currentFrame;
    
                            if ( keepRatio )
                            {
                                double ratio = (double) frame.Width / frame.Height;
                                Rectangle newRect = rect;
    
                                if ( rect.Width < rect.Height * ratio )
                                {
                                    newRect.Height = (int) ( rect.Width / ratio );
                                }
                                else
                                {
                                    newRect.Width = (int) ( rect.Height * ratio );
                                }
    
                                newRect.X = ( rect.Width - newRect.Width ) / 2;
                                newRect.Y = ( rect.Height - newRect.Height ) / 2;
    
                              
                                
                                    g.DrawImage(currentFrame, imagex, imagey, imgWidth, imgHeight);
                                     newWide = (int)(imgWidth - imagex);
                                     newHeight = (int) (imgHeight - imagey);
    
                                // g.DrawImage( frame, newRect.X + 1, newRect.Y + 1, newRect.Width - 2, newRect.Height - 2);
                            }
                            else
                            {
                                // draw current frame
                                try
                                {
                                    g.DrawImage(currentFrame, imagex, imagey, imgWidth, imgHeight);
                                    newWide = (int)(imgWidth - imagex);
                                    newHeight = (int)(imgHeight - imagey);
                                } catch( Exception err)
                                {
                                    MessageBox.Show(err.ToString());
                                }
    
                                // draw current frame
                                // g.DrawImage( frame, rect.X + 1, rect.Y + 1, rect.Width - 2, rect.Height - 2);
                            }
    
                            firstFrameNotProcessed = false;
     //                      currentPic = new Bitmap(currentFrame, newWide, newHeight);//   imgWidth, imgHeight);
                           
                        }
                        else
                        {
                            // create font and brush
                            SolidBrush drawBrush = new SolidBrush( this.ForeColor );
    
                            g.DrawString( ( lastMessage == null ) ? "Connecting ..." : lastMessage,
                                this.Font, drawBrush, new PointF( 5, 5 ) );
                            currentPic = currentFrame;//new Bitmap(currentFrame, this.Width, this.Height);
                            Console.WriteLine("in side the Else");
                            drawBrush.Dispose( );
                        }
                      
                    }
                   
                    borderPen.Dispose( );
                 
                }
    
    
            }
    
            // Update 

    Wednesday, July 24, 2019 10:58 PM
  • OK, so imgWidth and imgHeight represent the size of current video frame, with the zoom factor applied.  (One wonders why they didn't use a Size object for this.)  imagex and imagey represent the position, relative to the video player's window, where the upper left pixel of the video frame will be drawn.  If the image is zoomed, then the upper left pixel will be off the edge of the window, which is why the coordinates are negative.

    I think the problem you are trying to solve is, given a point within the video player's zoomed and panned window, what coordinate does that map to in the original bitmap?  Here is an example.  Your video frame is shown in green, the video player window is in black.  Let's say that your image is 800x600, the zoom factor is set to 4, and the zoom position was clicked at 50,50.  With that info, imgWidth will be 3200, imgHeight will be 2400.  imagex and imagey will be set to -200, as in this example:

    Now, let's say the user clicks at 150,40 in the player window.  It's easy to figure out what that maps to in the zoomed video frame: we just subtract imagex and imagey.  So 150-(-200) and 40-(-200) gives us 350,240.  So, that click maps to 350,240 in the zoomed bitmap.  From there, it's easy to figure out the location in the original bitmap: you divide by the zoom factor.  350/4 and 240/4 gives us (87,60).

    Thus, in your click handler:

        int origPosX = (arg.Location.X - videoSourcePlayer.imagex) / videoSourcePlayer.zoomFactor;
        int origPosY = (arg.Location.Y - videoSourcePlayer.imagey) / videoSourcePlayer.zoomFactor;

    When in doubt, draw a picture.


    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.



    • Edited by Tim Roberts Thursday, July 25, 2019 5:40 PM
    Thursday, July 25, 2019 5:39 PM
  • so how should my code look ?
    Thursday, July 25, 2019 9:22 PM
  • What do you mean?  I gave you the code.  Given a click in the zoomed video player window, the two lines of code at the end will give you the corresponding X and Y coordinate in the original bitmap.  I can't write the rest of the routine for you, because you haven't said what want to do with that information, and you really should be writing this yourself.

    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    Friday, July 26, 2019 5:52 AM
  • Tim, so this is the function I am using it for 

     double zoomingetback(int i2)
            {
                double answer = 0D;
                double l = 0D;
                double tempD = 0D;
                double[,] data = GetSnapshot();
    
    
                    for (int y = stIRList[i2].Y; y <= endIRList[i2].Y; y++)
                    {
                        for ( int x = stIRList[i2].X; x <= endIRList[i2].X; x++)
                        {
                        tempD = data[x, y];
                        answer = answer + tempD;
                            l++;
                        }
                    }
                
             
                answer = answer / l;
                return answer;
    
            }
    

    stIRList and endIRList is the point where the user is drawing the box on the video screen.

    so from your code should I do :

     
     double zoomingetback(int i2)
            {
                double answer = 0D;
                double l = 0D;
                double tempD = 0D;
                double[,] data = GetSnapshot();
                int origPosxStart =(int) ((stIRList[i2].X - videoSourcePlayer.imagex) / videoSourcePlayer.zoomFactor);
                int origPosYStart = (int)((stIRList[i2].Y - videoSourcePlayer.imagey) / videoSourcePlayer.zoomFactor);
    
                int origPosxStop = (int)((endIRList[i2].X - videoSourcePlayer.imagex) / videoSourcePlayer.zoomFactor);
                int origPosYStop = (int)((endIRList[i2].Y - videoSourcePlayer.imagey) / videoSourcePlayer.zoomFactor);
    
    
    
                for (int y = origPosYStart; y <= origPosYStop; y++)
                    {
                        for ( int x = origPosxStart; x <= origPosxStop; x++)
                        {
                        tempD = data[x, y];
                        answer = answer + tempD;
                            l++;
                        }
                    }
                
             
                answer = answer / l;
                return answer;
    
            }

    ?

    Friday, July 26, 2019 3:50 PM
  • it is still off.

    when I zoom in and draw my box around a dark pixel, I get wrong values:

     

    Friday, July 26, 2019 4:39 PM
  • that value should be for a bright picture not a dark one 
    Friday, July 26, 2019 4:40 PM
  • here is my code for the getting the 12 bit data:

      int global_x = 0;
            int global_y = 0;
            public double[,] GetSnapshot()
            {
                global_x = 0;
                global_y = 0;
                int rawImageSize = DetermineRawImageSize();
                byte[] temp = new byte[rawImageSize];
    
                float[] parameters = new float[1];
                parameters[0] = 1.5F;
                transfer.bits = new byte[getBufferSize()];
                FrameDescriptor frameDesc = new FrameDescriptor();
                //gets frame from camera
                ReturnCode rc = Api.GetNextFrame(m_hCamera, transfer.bits.Length, transfer.bits, ref frameDesc);
                int i4 = 0;
                int value2 = 0;
                global_y = videoSourcePlayer.Size.Height;
                global_x = videoSourcePlayer.Size.Width;
                double[,] returndata = new double[global_x, global_y];
    
                for (int y = 0; y < global_y; y++)
                {
                  for ( int x = 0; x < global_x; x++)
                    {
                        int value = ((transfer.bits[i4] << 8) + transfer.bits[i4 + 1]);
                        value2 = (value >> 4);
                        returndata[x,y]= value2;
                        i4 = i4 + 2;
                    }
                }
                return returndata;
            }
    
    

    Friday, July 26, 2019 4:41 PM
  • >  int value = ((transfer.bits[i4] << 8) + transfer.bits[i4+1]);

    Are you absolutely sure your camera is storing those pixels in big-endian format, with the most significant byte first?  That would be unusual these days.  Almost everything is little-endian.

    And it sure looks like the box in your image is drawn around a black section.


    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    Sunday, July 28, 2019 6:58 AM