影象插值演算法(最近臨插值演算法)
阿新 • • 發佈:2019-02-17
對於影象縮放演算法來說,最近臨插值演算法是最簡單的。最近臨插值演算法的原理是在原影象中找到最近臨的一個點,然後把這個點的畫素值插入到目標影象中,最近臨插值演算法優點是演算法簡單,易於實現,但是缺點是由於相鄰畫素點的畫素值相同,容易出現色塊現象。
那麼如何在原影象中找這個目標點呢,演算法公式如下:
src_x = dst_x * (src_width / dst_width); src_y = dst_y * (src_height / dst_height);
那麼算出來呢,可能會是小數點,需要四捨五入取整,那麼下面來看一個例子(一個3*3的矩陣):
234 38 22 67 44 12 89 65 63
這裡呢,我們需要將上面的一個3*3矩陣變換成一個4*4的矩陣,我們根據上面的公式來計算一下,首先是目標點為(0,0),那麼原影象的座標點為(0,0),那麼這個座標點的值就應該為234,然後再來看(0,1)這個座標點,那麼縱座標點還是0,但是橫座標點變成了1*(3/4) = 0.75,四捨五入得1,那麼得到的原影象座標為(0,1),那麼這個座標點值就應該為38,同理,最後得到的矩陣結果如下:
234382222 67441212 89656363 89656363
這部分測試程式碼如下:
關於對於影象的最近臨插值演算法我也寫了一個測試程式碼(只針對bmp格式的圖片,放大兩倍):#include <stdio.h> int main(int argc, char *argv[]) { int i, j, row, col; unsigned char mat1[3][3] = {{234, 38, 22}, {67, 44, 12}, {89, 65, 63}}; unsigned char mat2[4][4]; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { row = (int)(i * (3.0 / 4.0) + 0.5); col = (int)(j * (3.0 / 4.0) + 0.5); mat2[i][j] = mat1[row][col]; printf("%d\t", mat2[i][j]); } printf("\n"); } return 0; }
#include <stdio.h> #include <stdlib.h> struct bitmap_fileheader { unsigned short type; unsigned int size; unsigned short reserved1; unsigned short reserved2; unsigned int off_bits; } __attribute__ ((packed)); struct bitmap_infoheader { unsigned int size; unsigned int width; unsigned int height; unsigned short planes; unsigned short bit_count; unsigned int compression; unsigned int size_image; unsigned int xpels_per_meter; unsigned int ypels_per_meter; unsigned int clr_used; unsigned int clr_important; } __attribute__ ((packed)); void resize_near(void *dst, void *src, int dst_width, int dst_height, int src_width, int src_height) { int i, j, x, y; float scale_x, scale_y; char *buf1 = (char *)src, *buf2 = (char *)dst; scale_x = (float)src_width / (float)dst_width; scale_y = (float)src_height / (float)dst_height; for (i = 0; i < dst_height; i++) { for (j = 0; j < dst_width; j++) { y = (int)(i * scale_y + 0.5); x = (int)(j * scale_x + 0.5); buf2[i*dst_width*3 + j*3] = buf1[y*src_width*3 + x*3]; buf2[i*dst_width*3 + j*3 + 1] = buf1[y*src_width*3 + x*3 + 1]; buf2[i*dst_width*3 + j*3 + 2] = buf1[y*src_width*3 + x*3 + 2]; } } } int main(int argc, char *argv[]) { FILE *fp1, *fp2; struct bitmap_fileheader fh; struct bitmap_infoheader ih; void *buf1, *buf2; int src_width, src_height, dst_width, dst_height; if (argc < 2) return -1; fp1 = fopen(argv[1], "rb"); if (fp1 == NULL) { printf("open file %s failed!\n", argv[1]); return -1; } fread(&fh, 1, sizeof(struct bitmap_fileheader), fp1); fread(&ih, 1, sizeof(struct bitmap_infoheader), fp1); src_width = ih.width; src_height = ih.height; buf1 = malloc(ih.width * ih.height * (ih.bit_count / 8)); fread(buf1, 1, ih.width * ih.height * (ih.bit_count / 8), fp1); fp2 = fopen("resize.bmp", "wb"); if (fp2 == NULL) { printf("open file resize.bmp failed!\n"); return -1; } dst_width = src_width * 2; dst_height = src_height * 2; ih.width = dst_width; ih.height = dst_height; fh.size = fh.off_bits + ih.width * ih.height * (ih.bit_count / 8); fwrite(&fh, 1, sizeof(struct bitmap_fileheader), fp2); fwrite(&ih, 1, sizeof(struct bitmap_infoheader), fp2); buf2 = malloc(ih.width * ih.height * (ih.bit_count / 8)); resize_near(buf2, buf1, dst_width, dst_height, src_width, src_height); fwrite(buf2, 1, ih.width * ih.height * (ih.bit_count / 8), fp2); free(buf1); free(buf2); fclose(fp1); fclose(fp2); return 0; }
如果用opencv來做,那就很簡單了,直接使用opencv提供的cvResize函式,程式碼如下:
#include <highgui.h>
#include <cv.h>
int main(int argc, char *argv[])
{
IplImage *img1, *img2;
if (argc < 2)
return -1;
img1 = cvLoadImage(argv[1]);
img2 = cvCreateImage(CvSize(img1->width*2, img1->height*2), img1->depth, img1->nChannels);
cvResize(img1, img2, CV_INTER_LINEAR);
/* CV_INTER_NN
CV_INTER_LINEAR
CV_INTER_AREA
CV_INTER_CUBIC */
cvSaveImage("test.jpg", img2);
cvReleaseImage(&img1);
cvReleaseImage(&img2);
return 0;
}
其中引數CV_INTER_NN對應最近臨插值演算法,CV_INTER_LINEAR對應雙線性插值演算法。