2014-11-29 5 views
0

안녕하세요 저는 640x480 비트 맵 이미지를 320x240 이미지로 축소하는 프로그램을 진행하고 있습니다. 나는 잠시 동안이 문제를 연구 해왔다. 그러나 내가 발견 한 좋은 예는 모두 이미지의 크기를 늘리는 것이었다.이미지 크기를 축소하는 방법은 무엇입니까?

(여기 참조 : http://cboard.cprogramming.com/c-programming/154737-help-program-resize-image.html)

난 내에서 수행해야 할 것과 그 프로그램에서 수행 한 것을 번역 어려움을 겪고 있어요. 그러나 생성 된 이미지가 원래의 매우 왜곡 된 버전이며,

include stdio.h 
include stdlib.h 
include string.h 
include math.h 


pragma pack(push, 1) 
typedef struct tagBITMAPFILEHEADER 
{ 
unsigned short bfType; //specifies the file type 
unsigned int bfSize; //specifies the size in bytes of the bitmap file 
unsigned short bfReserved1; //reserved; must be 0 
unsigned short bfReserved2; //reserved; must be 0 
unsigned int bfOffBits; //species the offset in bytes from the bitmapfileheader to the bitmap bits 
} BITMAPFILEHEADER; 
pragma pack(pop) 

pragma pack(push, 1) 
typedef struct tagBITMAPDIBHEADER 
{ 
unsigned int biSize; //specifies the number of bytes required by the struct 
int biWidth; //specifies width in pixels 
int biHeight; //species height in pixels 
unsigned short biPlanes; //specifies the number of color planes, must be 1 
unsigned short biBitCount; //specifies the number of bit per pixel 
unsigned int biCompression;//spcifies the type of compression 
unsigned int biSizeImage; //size of image in bytes 
int biXPelsPerMeter; //number of pixels per meter in x axis 
int biYPelsPerMeter; //number of pixels per meter in y axis 
unsigned int biClrUsed; //number of colors used by th ebitmap 
unsigned int biClrImportant; //number of colors that are important 
} BITMAPDIBHEADER; 
pragma pack(pop) 

pragma pack(push, 1) 
typedef struct 
{ 
int rgbtBlue; 
int rgbtGreen; 
int rgbtRed; 
} 
RGBTRIPLE; 
pragma pack(pop) 

int main() 
{ 
FILE *input, *output; 
BITMAPDIBHEADER inputdibHeader; 
BITMAPFILEHEADER inputfileHeader; 
BITMAPDIBHEADER outputdibHeader; 
BITMAPFILEHEADER outputfileHeader; 

int greenValue = 0; 
int blueValue = 0; 
int redValue = 0; 
fopen_s(&output, "test.bmp", "wb"); 
if (output == NULL){ 
    return NULL; 
} 
fopen_s(&input, "lolcat.bmp", "rb"); 
if (input == NULL) 
    return NULL; 

rewind(input); // rewind the file before reading it again 
fread(&(inputfileHeader), sizeof(BITMAPFILEHEADER), 1, input); 
fread(&(inputdibHeader), sizeof(BITMAPDIBHEADER), 1, input); 
rewind(input); // rewind the file before reading it again 
fread(&(outputfileHeader), sizeof(BITMAPFILEHEADER), 1, input); 
fread(&(outputdibHeader), sizeof(BITMAPDIBHEADER), 1, input); 





outputdibHeader.biWidth = inputdibHeader.biWidth *.5; 
outputdibHeader.biHeight = inputdibHeader.biHeight *.5; 
outputfileHeader.bfSize = outputdibHeader.biWidth * outputdibHeader.biHeight; 
outputdibHeader.biSizeImage = inputdibHeader.biSizeImage *.5; 
fwrite(&(outputfileHeader), sizeof(BITMAPFILEHEADER), 1, output); 
fwrite(&(outputdibHeader), sizeof(BITMAPDIBHEADER), 1, output); 

rewind(input); 
fseek(input, inputfileHeader.bfOffBits, SEEK_SET); 
fseek(output, outputfileHeader.bfOffBits, SEEK_SET); 
int oldheight = inputdibHeader.biHeight; 
int oldwidth = inputdibHeader.biWidth; 
int i; 
int timeswriten = 0; 
int oldPad = (4 - ((inputdibHeader.biWidth * sizeof(RGBTRIPLE)) % 4)) % 4; 
int newPad = (4 - ((outputdibHeader.biWidth * sizeof(RGBTRIPLE)) % 4)) % 4; 

// iterate over infile's scanlines 
for (int i = 0; i < abs(oldheight); i++) 
{ 
    if (i % 2){ 


     // iterate over pixels in scanline 
     for (int j = 0; j < oldwidth; j++) 
     { 
      // temporary storage 
      RGBTRIPLE triple; 
      fread(&triple, sizeof(RGBTRIPLE), 1, input); 
      if (j % 2){ 
       fwrite(&triple, sizeof(RGBTRIPLE), 1, output); 
      } 
      // skip over any input padding 
      fseek(input, oldPad, SEEK_CUR); 


     } 
    } 
    } 

    fclose(input); 
    fclose(output); 

} 

현재이 코드가 유효한 비트 맵 이미지를 생성한다 : 여기서 SOFAR 내 코드이다. 임 꽤 확신이 내 새로운 이미지에서 픽셀을 생략하는 방법으로 인해 있지만이 올바른 접근 방식에 있어야하는지 잘 모르겠습니다. 내 모든 질문을 통해 누구나 내가 어떻게 픽셀을 생략해야한다고 설명 할 수 있습니까?

업데이트

지금 내가 무엇을 목표로하고하는 것은 하나 개의 픽셀에 평균 2 × 2 픽셀 것을 알고 있지만 나는이 작업을 수행하는 방법에 대한 좋은 예를 찾을 수 없습니다. 이 과정을 설명해 줄 수 있습니까?

업데이트 2PeterT에게 감사드립니다. 다음 코드는 내 출력에 의해 정확하다는 것을 알고 있습니다.

RGBTRIPLE *line_a = (RGBTRIPLE*)malloc(inputdibHeader.biWidth * sizeof(RGBTRIPLE)); /* check malloc() */ 
RGBTRIPLE *line_b = (RGBTRIPLE*)malloc(inputdibHeader.biWidth *sizeof(RGBTRIPLE)); /* check malloc() */ 
RGBTRIPLE *dest_line = (RGBTRIPLE*)malloc(outputdibHeader.biWidth * sizeof(RGBTRIPLE)); 

    /* move through the target array line by line, consuming two lines from the source 
    image at a time */ 
    /* also assuming you verified the source image is exactly 2x the size of the dest 
    malloc() */ 
for (i = 0; i < outputdibHeader.biHeight; ++i) 
{ 
    fread(&(line_a), sizeof(RGBTRIPLE), inputdibHeader.biWidth, input); /* read scanline & advance file pointer, err check in func */ 
    fread(&(line_b), sizeof(RGBTRIPLE), inputdibHeader.biWidth, input);/* read scanline & advance file pointer, err check in func */ 
    for (j = 0; j < outputdibHeader.biWidth; ++j) 
    { 
     bilinear_filter(&(dest_line[j]), &(line_a[j * 2]), &(line_a[(j * 2) + 1]), &(line_b[j * 2]), &(line_b[(j * 2) + 1])); 
    } 
    fwrite(&(dest_line), sizeof(RGBTRIPLE), outputdibHeader.biWidth, output); 
    /* or something... point is we're creeping through the files scaline by scanline, 
    and letting another function handle it to keep this code more intelligble */ 
} 

fclose(input); 
fclose(output); 

} 
void bilinear_filter(RGBTRIPLE *dest, RGBTRIPLE *A, RGBTRIPLE *B, RGBTRIPLE *C, RGBTRIPLE *D) 
{ 

/* assuming 0888 ARGB */ 
dest->Red = (A->Red + B->Red + C->Red + D->Red)/4; 
dest->Green = (A->Green + B->Green + C->Green + D->Green)/4; 
dest->Blue = (A->Blue + B->Blue + C->Blue + D->Blue)/4; 

} 

나는이 문제가 지금 여기 내 헤더 생성에 거짓말입니다 수 있습니다 생각

fread(&(inputHeader), sizeof(TwoHeader), 1, input); 
inputfileHeader = inputHeader.fileHeader; 
inputdibHeader = inputHeader.dibHeader; 
rewind(input); // rewind the file before reading it again 
fread(&(outputHeader), sizeof(TwoHeader), 1, input); 
outputfileHeader = outputHeader.fileHeader; 
outputdibHeader = outputHeader.dibHeader; 


outputdibHeader.biWidth = inputdibHeader.biWidth *.5; 
outputdibHeader.biHeight = inputdibHeader.biHeight *.5; 
//outputfileHeader.bfSize = inputfileHeader.bfSize - (inputdibHeader.biWidth*inputdibHeader.biHeight) + outputdibHeader.biWidth*outputdibHeader.biHeight; 
outputfileHeader.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPDIBHEADER)+outputdibHeader.biSizeImage; 
//outputdibHeader.biSizeImage = inputdibHeader.biSizeImage * .25; 
//outputdibHeader.biXPelsPerMeter = inputdibHeader.biXPelsPerMeter * .5; 
//outputdibHeader.biYPelsPerMeter = inputdibHeader.biYPelsPerMeter * .5; 
//fwrite(&(outputfileHeader), sizeof(BITMAPFILEHEADER), 1, output); 
//fwrite(&(outputdibHeader), sizeof(BITMAPDIBHEADER), 1, output); 
fwrite(&(outputHeader), sizeof(TwoHeader), 1, output); 
rewind(input); 
fseek(input, inputfileHeader.bfOffBits, SEEK_SET); 
fseek(output, outputfileHeader.bfOffBits, SEEK_SET); 

사면 모든 의견 나는 확실하지 오전의 대부분은 이전 코드 또는 코드.

+1

아마도 문제와 관련이 없으므로 (더 자세히 설명하고 싶을 수 있습니다.) 이미지의 너비와 높이를 반으로 줄이면 새로운 'biSizeImage'는 1/2이 아니며 실제로는 1/2 * 1/2 = 1/4 크기. 주로 RGB 트라이 플릿은'int'가 아닌'unsigned char'이어야합니다. – usr2564301

+1

다양한 수준의 효율성과 품질을 갖춘 알고리즘이 많이 있습니다. 꽤 광범위한 주제입니다. 이것은 당신에게 생각할 몇 가지 사항을 줄 수 있습니다 : http://stackoverflow.com/questions/6133957/image-downsampling-algorithms –

+0

@RetiredNinja 적어도 많은 도움을 주셔서 감사합니다, 지금은 내가 뭘 찾아야하는지에 대한 아이디어가 있습니다. 불행하게도이 페이지는 실제로 알고리즘이 어떻게 사용되는지에 대한 좋은 예는 보여주지 않습니다. 나는 하나를 찾을 것이다. 당신이 알고있는 일이 있다면 당신은 그것을 연결시킬 수 있습니다. – Noob

답변

4

"지금 당분간이 문제를 조사해 왔습니다."... 정말로 요?/눈썹 올리기 /;)

새로운 픽셀은 실제로 네 픽셀의 평균이며 이전 네 픽셀의 중앙에 위치합니다.

휠을 다시 발명해야합니까? 난 그냥 이것에 대한 고체 라이브러리를 사용하고 해결하는 다른 문제에 내 에너지를 집중할 것 :

https://github.com/nothings/stb

보간의 기본 방법에 큰 위키 피 디아 기사있다 :

http://en.wikipedia.org/wiki/Image_scaling

가 2D 이미지를 다운 샘플링하는 것은 컴퓨터 과학 분야에서 40 년 이상 된 오래된 문제입니다. 폴리 (Foley)는 그의 책 "컴퓨터 그래픽 (Computer Graphics)"에서 그것을 다룬다. 훌륭한 책이다. 당신은 적어도 두 개의 주사선을 저장해야합니다 다운 샘플링 간단한 선형 들어

: 코드에 대해서는

. 귀하의 코드를 더 모듈 식으로 분해하는 것이 좋습니다. 다음은 매우 간단한 구현입니다.

triple *line_a = (triple*)malloc(...) /* check malloc() */ 
triple *line_b = (triple*)malloc(...) /* check malloc() */ 
triple *dest_line = etc... 

/* move through the target array line by line, consuming two lines from the source 
    image at a time */ 
/* also assuming you verified the source image is exactly 2x the size of the dest 
    malloc() */ 
for (i = 0; i < dest_height; ++i) 
{ 
    read_line(line_a); /* read scanline & advance file pointer, err check in func */ 
    read_line(line_b); /* read scanline & advance file pointer, err check in func */ 
    for (j = 0; j < dest_width; ++j) 
    { 
     bilinear_filter(&(dest_line[j]), &(line_a[j*2]), &(line_a[(j*2)+1]), &(line_b[j*2]), &(line_b[(j*2)+1])); 
    } 
    write_line_to_file(dest_line, fp); /* or something... point is we're creeping through the files scaline by scanline, and letting another function handle it to keep this code more intelligble */ 
} 
: 
: 
void bilinear_filter(triple *dest, triple *A, triple *B, triple *C, triple *D) 
{ 

    /* assuming 0888 ARGB */ 
    dest->r = (A->r + B->r + C->r + D->r)/4; 
    dest->g = (A->g + B->g + C->g + D->g)/4; 
    dest->b = (A->b + B->b + C->b + D->b)/4; 

} 

이제 색상 채널을 삽입하는 방법은 다양합니다.눈에 보이는 스펙트럼의 에너지 방출이나 인쇄물/필름의 색 영역 곡선 등을 고려한 이론이 있습니다. 대부분의 경우 r/g/b를 독립적으로 스케일링하지 않습니다. 눈의 감도에 대한 세 가지 값. 위의 방법은 바이 리니어 필터가 하나의 새로운 픽셀을 생성하기 위해 4 픽셀의 데이터를 읽어야한다는 지적에 불과합니다.

도움이 되었기를 바랍니다.

+0

응답 해 주셔서 감사합니다. 죄송합니다 그것에 대해 더 빨리 언급하지 않았습니다. 나는 아직 귀하의 게시물을 볼 수 없었지만, 나는 복용량이 언뜻보기에 매우 도움이되었습니다. 내가 더 볼 수 있으면 아픈 두 번째 게시물을 만들 것입니다. 게시물에 다시 한 번 감사드립니다. – Noob

+0

방금 ​​내 프로젝트에 코드를 구현했습니다. 조금 생각한 후에 기능적 bmp 파일을 만들어야합니다. 그러나 제작 된 그림이 정확하지 않거나 올바른 크기가 아닙니다. 당신이 눈에 띄게 잘못된 것을 본다면 현재 코드로 내 질문을 업데이트했습니다. 지금까지 도움을 주셔서 감사하지 않더라도. – Noob

+0

비트 맵으로 작업 한 이후 오랜 시간이 걸렸지 만 헤더가 까다 롭다는 것을 기억합니다. 많은 필드를 주석 처리 했으므로 입력 파일의 속성이 여전히 있음을 의미합니다. 그것은 문제의 일부입니다. 내가 당신이라면 모든 비트 맵 필드를 인쇄하는 debugPrintHeader() 함수를 작성하여 올바르게 작성했는지 확인할 수 있습니다. 16 진수 편집기를 사용하여 파일에 쓰는 내용이 헤더가 올바른지 확신 할 때까지 메모리에있는 내용과 일치하는지 확인할 수도 있습니다. 행운을 빕니다! – PeterT

관련 문제