Thread: Shifting an image down a row

  1. #1
    Registered User
    Join Date
    Jul 2006
    Posts
    49

    Question Shifting an image down a row

    I've been given someone elses code and I'm required to use their code and write new code in order to shift an image down a row....and later on, be able to shift the image back up a row. I'm pretty lost in their code and don't know exactly where to begin. Some image properties that I've been given with their code are:
    Code:
       ip.image_buffer = (unsigned char *) options->image_origin;
       ip.image_size.cx = options->image_width;
       ip.image_size.cy = options->image_height;
       ip.image_pitch = options->image_line_delta;
       ip.y_mask = 0xffffffff;
       ip.x_min = 0;
       ip.x_max = ip.image_size.cx - 1;
       ip.y_min = 0;
       ip.y_max = ip.image_size.cy - 1;
    	ip.num_pixels = ip.image_pitch * ip.image_size.cy;
       ip.bounded_frame = 1;
    	ip.linear = 1;
    
    and here is part of a method that might be useful...but I'm not too sure yet:
    
    int row, col;
        unsigned char min;
    	unsigned char *out_ptr;
    	unsigned char *row_n1, *row_0, *row_p1;
    	unsigned char col_min_n1, col_min_0, col_min_p1;
    
    	ia_get_image_params(&ip);
    
    	for(row = 1; row < ip.image_size.cy - 1; row++)
        {
    		out_ptr = &ip.image_buffer[row * ip.image_size.cx + 1];
    
    		row_n1 = &ip.original_image_buffer[(row-1) * ip.image_size.cx];
    		row_0 = row_n1 + ip.image_size.cx;
    		row_p1 = row_0 + ip.image_size.cx;
    
          for(col = 1; col < ip.image_size.cx - 1; col++)
          {
    			min = col_min_n1;
    			if (col_min_0 < min) min = col_min_0;
    			if (col_min_p1 < min) min = col_min_p1;
    
    			*out_ptr++ = min;
    			col_min_n1 = col_min_0;
    			col_min_0 = col_min_p1;
          }
    	}
    I've been told that ip.image_buffer is the start of the image. That's about all the info I've been given and I'm not too sure I have enough to complete this task, but any help in the right direction is appreciated. Thanks
    Last edited by Salem; 08-01-2006 at 03:07 PM. Reason: Please use the code tags in future!

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    What do you mean by "shift one row"? Are you taking the bottom row and placing it at the top, and dropping each row down one? You might consider starting with a 2D array, and "shifting" that. Then translating that code to handle your image structure or what have you.


    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User
    Join Date
    Jul 2006
    Posts
    49
    If I had a 25x25 image, and moved it from row 1 to row 2, the image would start in row 2 and still end in row 25. Basically cutting off the bottom row.

    If I know that ip.image_buffer is the start of the image, how would I shift it down a row? I'd like to avoid starting with a 2D array if possible. Thanks for the input.

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Ok, so you're removing a row then? In C, we usually begin counting at zero, not 1. You'll have problems with that if you use arrays for example. The problem you will encounter here, if you're simply lopping off a row, is that unless you store it some place else, you can't shift back.

    The reason you should start with an array, is to show that you understand the concept. Once you're clear on how that works, it should be simple to translate it to your image, because it'll be nearly identical.
    Code:
    for each
        copy here + 1 to here
    here = unused
    Now with an array, there is no such thing as "unused", so you have to set up a marker of some kind to denote it. The same thing will happen with your image. You'll have to adjust your header and footer, which keep track of the size of your image. That is to say, you'll be updating everything past the end of the "data", by shifting it also, or, you'll be inserting your "end of data" marker. You'll also need to update your "rows" counter. Assuming of course that your image actually keeps track of these things.

    Quzah.
    Hope is the first step on the road to disappointment.

  5. #5
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Sounds like the first step is to find the size of each pixel. Then you should be able to do:
    Code:
    memmove(ip.image_buffer, ip.image_buffer + ip.image_size.cx * WHATEVER_PIXEL_SIZE_IS, ip.image_size.cx * WHATEVER_PIXEL_SIZE_IS);
    ip.image_size.cy--;
    ip.y_max--;
    If you understand what you're doing, you're not learning anything.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Unless you have pointers to each row, basically what you have is a bunch of memcpy calls to move each row down to the next row (starting at the bottom).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Quote Originally Posted by Salem
    Unless you have pointers to each row, basically what you have is a bunch of memcpy calls to move each row down to the next row (starting at the bottom).
    I thought about that, but it concerned me that ip.image_buffer might be dynamically allocated, which means you can't just make it point to the 2nd row without some hassle.

    And since the image is just one big buffer, I figured why not just use one call to memmove() to get the job done?
    If you understand what you're doing, you're not learning anything.

  8. #8
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Nevermind, scratch my solution. I read wrong and mine shifts the image UP instead of DOWN. Sorry.

    The code I posted should work for shifting the other way also though. Just memmove() forward into the buffer, instead of backward. The number of bytes to copy should be the image size minus the size of one row. Leave the number of rows alone since that's not changing.

    The memmove() will, in effect, copy over the last row of the image with the row above it, and so on up the image.
    Last edited by itsme86; 08-01-2006 at 03:31 PM.
    If you understand what you're doing, you're not learning anything.

  9. #9
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Nevermind, scratch my solution. I read wrong and mine shifts the image UP instead of DOWN. Sorry.
    Geez. What were you thinking.

    If you shift down one row you will shift one row out of the array. This is the same as bit shifting too far for the data type to handle. For right shifts the rightmost bit will be shifted out of the value and for left shifts, the leftmost will be shifted out. You cannot shift a 25x25 image down one row and then back up, w/o first placing the outgoing row in memory somewhere so you can stick it back in later.

    However if you are drawing from an array in memory, then you can shift the starting offset down one row which will shift the image up one row and vice versa.


    Code:
    int iOffset=0;
    int iStartOffset=iOffset;
    int iX=0,iY=0;
    
    for (int i=0;i<iImageSize;i++)
    {
      PutPixel(iX,iY,pImage[iOffset]);
      iOffset++;
      iCol++;
      if (iCol>iImageWidth)
      {
         iCol=0;
         iRow++;
         iStartOffset+=iImageWidth;
         iOffset=iStartOffset;
      }
      if (iRow>iImageHeight) break;
    }
    If you change iOffset to iOffset=iImageWidth*(desired_row) this will cause the drawing to start desired_row(s) into the image.

    So:

    Code:
    iOffset+=iImageWidth;   //down 1 row
    iOffset-=iImageWidth; //up 1 row
    That code assumes the drawing always starts at 0,0.

    A better way would be to use scroll values for x and y and compute starting row and column based on these value. Then compute the starting offset from the starting row and column and save it in iOffset and iStartOffset. The rest is already done. You may want to check if row>iWindowHeight and if col>iWindowWidth. If so, you need to react accordingly. There is no need to actually alter the memory, just alter what is displayed.

    This is a good pre-cursor for a tile engine. Rendering a bitmap is no different than a tile engine except that each 'tile' in a bitmap is exactly 1 pixel. Tile's are just larger 'pixels' if you will when it comes down to rendering them on screen. The memory operations are nearly identical. Rendering bitmaps is 'draw pixel from memory at x,y' and rendering tiles is 'draw tile (array of pixels) from memory at x,y'. But they are both 'paint by the number'.


    In this method there are no memory write's and the memory is never changed. What is changed is where we start 'rendering from memory'. This uses a linear array with no multiplies in the loop. If you add keyboard input for ways to scroll the image, it will scroll so fast you will prob need to put a delay in the loop.
    Last edited by VirtualAce; 08-02-2006 at 02:10 AM.

  10. #10
    Registered User
    Join Date
    Jul 2006
    Posts
    49

    Question

    I guess I should have been a little more clear about the image shifting down a row. The visual shift is not the important part. Once the image is shifted down, then I will be using an image manipulation of either erosion or dilation (separate methods already written) on the image. Then I need to shift the image back up a row in order to do a second erosion or dilation. Then I have to shift the image up another row for a third manipulation and then down 2 rows for a fourth manipulation. So should I follow with more of what itsme86 had mentioned or Bubba? And for Bubba's, is PutPixel a method that I need to write?

    Thanks for all the input.

  11. #11
    Registered User
    Join Date
    Jul 2006
    Posts
    49

    Question

    Is this the right concept?

    code:

    if (count == 0) /* shift down a row on first pass */
    {
    memmove(ip.image_buffer, ip.image_buffer + ip.image_size.cx * 1, ip.image_size.cx - 1 * 1);
    ip.image_size.cy--;
    ip.y_max--;
    }

    if (count == 1) /* shift up a row on second pass */
    {
    memmove(ip.image_buffer, ip.image_buffer + ip.image_size.cx * 1, ip.image_size.cx * 1);
    ip.image_size.cy--;
    ip.y_max++;
    }

  12. #12
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    The problem with my memmove() method is that, like I said, it overwrites the last row in the direction you're shifting. This makes it impossible to get that row back when you shift the other way unless you store that row of the image somewhere else before the memmove() (or increase the image_buffer size and move the entire image instead of the whole image minus the last row).
    If you understand what you're doing, you're not learning anything.

  13. #13
    Registered User
    Join Date
    Jul 2006
    Posts
    49

    Question

    If I use the memmove() method, how could I store that last row of the image and then "append" it back in order to reshift? Or is increasing the image_buffer size and moving the entire image the more efficient way to do it? I know that the more efficient and faster code is always the best, so that would definitely be the most helpful right now.

  14. #14
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Are you trying to scroll the image vertically, so that the bottom of the image reappears at the top of the image (like some old TV on the blink) ?

    It's just like swapping two variables - you save one bit in a temporary buffer, move the rest, then copy the temp into the space vacated.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  15. #15
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    I would definitely go with Bubba's method. It doesn't require moving the image around in memory. It just creates a "window" that outlines the currently valid part of the image_buffer that contains the image.

    That would definitely be the fastest, but will require you to look at the window logic in other parts of the program.
    If you understand what you're doing, you're not learning anything.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem reading tiff image files?
    By compz in forum C++ Programming
    Replies: 9
    Last Post: 10-30-2009, 04:17 AM
  2. reading pictures and array
    By sunoflight77 in forum C++ Programming
    Replies: 0
    Last Post: 05-09-2005, 03:16 PM
  3. Animation not working....
    By aquinn in forum C Programming
    Replies: 7
    Last Post: 02-19-2005, 05:37 AM
  4. libtiff: TIFFWriteRGBAImage()?
    By dug in forum Game Programming
    Replies: 1
    Last Post: 07-09-2003, 09:01 AM
  5. Is there a bug in this part of my algorithm for connect 4?
    By Nutshell in forum Game Programming
    Replies: 8
    Last Post: 04-28-2002, 01:58 AM