在SDL中旋转图像

时间:2014-05-18 18:40:32

标签: c linux sdl

我有工作程序模糊图像,我必须做出类似旋转图像的功能。我编写了反转二维数组的算法:

int old_data[height][width];
int new_data[width][height];

for(i=0; i<width; i++) {
    for(j=0; j<height; j++) {
        new_data[i][j] = old_data[height-1-j][i];
    }
}

这是我的模糊计划:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>

void Filter(unsigned char * buf, int width, int height, int size, char bpp, unsigned short pitch)
{
  printf("%d %d %d\n", width, height, (int)bpp);
  unsigned char *tmp = (unsigned char*)malloc(pitch*height);
  memcpy(tmp, buf, pitch*height);
  int pix[9], sum, count;
  int x, y, k, i;
  for(y=0; y<height; ++y)
    for(x=0; x<width; ++x)
    {

      pix[0] = y*pitch + x*bpp; 
      pix[1] = pix[0] - pitch; 
      pix[2] = pix[0] + pitch; 
      pix[3] = pix[1] - bpp; 
      pix[4] = pix[1] + bpp; 
      pix[5] = pix[0] - bpp; 
      pix[6] = pix[0] + bpp; 
      pix[7] = pix[2] - bpp; 
      pix[8] = pix[2] + bpp; 

      for(k=0; k<bpp; ++k)
      {
        sum = 0;
        count = 0;
        for(i=0; i<9; ++i)
        {
          if(pix[i]>=0 && pix[i]<pitch*height)
          {
            sum += (int) (tmp[ pix[i]+k ]);
            ++count;
          }
        }
        sum /= count;
        buf[ pix[0]+k ] = (unsigned char)sum;
      }
    }
}


SDL_Surface* Load_image(char *file_name)
{
        /* Open the image file */
        SDL_Surface* tmp = IMG_Load(file_name);
        if ( tmp == NULL ) {
            fprintf(stderr, "Couldn't load %s: %s\n",
                    file_name, SDL_GetError());
                exit(0);
        }
        return tmp; 
}

void Paint(SDL_Surface* image, SDL_Surface* screen)
{
        SDL_BlitSurface(image, NULL, screen, NULL);
        SDL_UpdateRect(screen, 0, 0, 0, 0);
};





int main(int argc, char *argv[])
{
    Uint32 flags;
    SDL_Surface *screen, *image;
    int depth, done;
    SDL_Event event;

    /* Check command line usage */
    if ( ! argv[1] ) {
        fprintf(stderr, "Usage: %s <image_file>, (int) size\n", argv[0]);
        return(1);
    }

    if ( ! argv[2] ) {
        fprintf(stderr, "Usage: %s <image_file>, (int) size\n", argv[0]);
        return(1);
    }

    /* Initialize the SDL library */
    if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
        fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
        return(255);
    }

    flags = SDL_SWSURFACE;
    image = Load_image( argv[1] );
    printf( "\n\nImage properts:\n" );
    printf( "BitsPerPixel = %i \n", image->format->BitsPerPixel );
    printf( "BytesPerPixel = %i \n", image->format->BytesPerPixel );
    printf( "width %d ,height %d \n\n", image->w, image->h );       

    SDL_WM_SetCaption(argv[1], "showimage");

    /* Create a display for the image */
    depth = SDL_VideoModeOK(image->w, image->h, 32, flags);
    /* Use the deepest native mode, except that we emulate 32bpp
       for viewing non-indexed images on 8bpp screens */
    if ( depth == 0 ) {
        if ( image->format->BytesPerPixel > 1 ) {
            depth = 32;
        } else {
            depth = 8;
        }
    } else
    if ( (image->format->BytesPerPixel > 1) && (depth == 8) ) {
            depth = 32;
    }
    if(depth == 8)
        flags |= SDL_HWPALETTE;
    screen = SDL_SetVideoMode(image->w, image->h, depth, flags);
    if ( screen == NULL ) {
        fprintf(stderr,"Couldn't set %dx%dx%d video mode: %s\n",
            image->w, image->h, depth, SDL_GetError());
    }

    /* Set the palette, if one exists */
    if ( image->format->palette ) {
        SDL_SetColors(screen, image->format->palette->colors,
                  0, image->format->palette->ncolors);
    }


        printf("$$$$$$ %u \n", image->pitch);
    /* Display the image */
    Paint(image, screen);

    done = 0;
    int size =atoi( argv[2] );
    printf("Actual size is: %d\n", size);
    while ( ! done ) {
        if ( SDL_PollEvent(&event) ) {
            switch (event.type) {
                case SDL_KEYUP:
                switch (event.key.keysym.sym) {
                    case SDLK_ESCAPE:
                    case SDLK_TAB:
                    case SDLK_q:
                    done = 1;
                    break;
                    case SDLK_SPACE:
                    case SDLK_f:
                    SDL_LockSurface(image);

                    printf("Start filtering...  ");
                    Filter(image->pixels,image->w,image->h, size, image->format->BytesPerPixel, image->pitch);
                    printf("Done.\n");

                    SDL_UnlockSurface(image);

                    printf("Repainting after filtered...  ");
                    Paint(image, screen);
                    printf("Done.\n");

                    break;
                    case SDLK_r:
                    printf("Reloading image...  ");
                    image = Load_image( argv[1] );
                    Paint(image,screen);
                    printf("Done.\n");
                    break;
                    case SDLK_PAGEDOWN:
                    case SDLK_DOWN:
                    case SDLK_KP_MINUS:
                    size--;
                    if (size==0) size--;
                    printf("Actual size is: %d\n", size);
                        break;
                    case SDLK_PAGEUP:
                    case SDLK_UP:
                    case SDLK_KP_PLUS:
                    size++;
                    if (size==0) size++;
                    printf("Actual size is: %d\n", size);
                    break;      
                   case SDLK_s:
                    printf("Saving surface at nowy.bmp ...");
                    SDL_SaveBMP(image, "nowy.bmp" ); 
                    printf("Done.\n");
                    default:
                    break;
                }
                break;
//              case  SDL_MOUSEBUTTONDOWN:
//              done = 1;
//              break;
                            case SDL_QUIT:
                done = 1;
                break;
                default:
                break;
            }
        } else {
            SDL_Delay(10);
        }
    }
    SDL_FreeSurface(image);
    /* We're done! */
    SDL_Quit();
    return(0);
}

有人可以帮我改变旋转图像的滤镜功能吗?

1 个答案:

答案 0 :(得分:2)

这与SDL无关,它只是一个简单的转换。

让我们考虑一下这个简单的图片(x?y?表示坐标):

+-------+-------+-------+-------+-------+
| x0,y0 | x1,y0 | x2,y0 | x3,y0 | x4,y0 |
+-------+-------+-------+-------+-------+
| x0,y1 | x1,y1 | x2,y1 | x3,y1 | x4,y1 |
+-------+-------+-------+-------+-------+
| x0,y2 | x1,y2 | x2,y2 | x3,y2 | x4,y2 |
+-------+-------+-------+-------+-------+
| x0,y3 | x1,y3 | x2,y3 | x3,y3 | x4,y3 |
+-------+-------+-------+-------+-------+

并且您希望将其向右旋转90度。这意味着左上角的像素将是新的右上角,左下角将是新的左上角。所以它看起来像这样:

+-------+-------+-------+-------+
| x0,y3 | x0,y2 | x0,y1 | x0,y0 |
+-------+-------+-------+-------+
| x1,y3 | x1,y2 | x1,y1 | x1,y0 |
+-------+-------+-------+-------+
| x2,y3 | x2,y2 | x2,y1 | x2,y0 |
+-------+-------+-------+-------+
| x3,y3 | x3,y2 | x3,y1 | x3,y0 |
+-------+-------+-------+-------+
| x4,y3 | x4,y2 | x4,y1 | x4,y0 |
+-------+-------+-------+-------+

所以你需要做的是获取原始图像的宽度和高度,并创建一个宽度和高度相反的目标位图(因此宽度变为高度,反之亦然),否则目标位图应为与源位图相同。

然后声明一个包含目标X坐标的变量,并将其初始化为最大目标X坐标(在上面的示例中,它将初始化为3)。创建两个嵌套循环,外部(例如)遍历X坐标(从零到源位图的宽度),内部执行相同但是对于Y坐标。

在内部循环中,您获取源X,Y像素并将其放置在目标-X,source-X坐标上的目标位置(请注意,您使用源X作为目标Y),并减小目标X坐标。如果目标X坐标为零,则将其重置为最大目标坐标(例如,在示例中为3)。

要旋转270度(或者更确切地说,-90度),如果你让我漂移,那么它会相同但有点相反。


要旋转180度,您可以进行两次90度旋转,或者第一次垂直镜像,然后水平镜像。


另请注意,上面的算法对于所有尺寸和尺寸的图像都是通用的。


旋转的伪代码:

bitmap create_bitmap(width, height) { ... }

int get_pixel(bitmap, x, y) { ... }

void set_pixel(bitmap, x, y) { ... }

bitmap rotate_image(bitmap source)
{
    bitmap destination;

    source_width  = source.width;
    source_height = source.height;

    /* Switch place of width and height */
    destination = create_bitmap(source_height, source_width);

    for (x = 0; x < source_width; ++x)
    {
        dest_x = source_height - 1;

        for (y = 0; y < source_height; ++y)
        {
            source_pixel = get_pixel(source, x, y);

            set_pixel(destination, dest_x, x);

            dest_x = dest_x - 1;
        }
    }

    return destination;
}