0%

基于拉格朗日插值的图片缩放算法

Welcome to to my blog! If you get any problems when read this post, you can ask me on GitHub.

基于拉格朗日插值的bmp图片缩放算法

题目要求

  • 本题考查Lagrange插值的应用
  • 采用Lagrange插值BMP图像进行缩放处理
  • 要求
    • C语言等高级语言编程
    • 能够指定待缩放图像
    • 能够指定目标图像尺寸
    • 能够指定插值所需样本点数
    • 能够保存缩放图像
  • 功能
    • 选做功能1: 灰度图像的缩放
    • 选做功能2: 彩色图像的缩放

题目分析

  1. BMP文件的表示
    • BMP文件包括文件头、信息头、调色板、图像数据
    • 文件头一般14个字节(详见后文)
    • 信息头一般40个字节(详见后文)
    • 彩色图像一般无调色板,灰度图像调色板一般为 unsigned char clrPal[1024] = {0,0,0,0, 1,1,1,0, …, 255,255,255,0}
      图像数据(见后文)
      BMP文件
  2. 图像数据表示
    • 灰度图像:表示为二维数组,数组元素称为像素,像素值为0~255的整数(0最暗, 255最亮)数组行数等于图像高度,数组列数等于图像宽度实际采用一维数组存储,逐行存储各像素;每行元素个数必为4的倍数,否则补充1~3个元素使满足此条件
    • 彩色图像:等价于三个灰度图像,对应蓝绿红三原色表示为“二维数组” ,数组元素(即像素)为三个0~255的整数数组行数等于图像高度,数组列数等于图像宽度实际采用一维数组存储,逐行存储各像素(每个像素表示为3个0~255的整数);每行元素个数必为4的倍数,否则补充1~3个元素使满足此条件
  3. 算法解析
    • 留坑…

代码实现

代码连接.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <stdlib.h>
#define mac(a, s) a=(U8*)malloc(sizeof(U8)*s)
using namespace std;
typedef unsigned char U8;
typedef unsigned short U16;
typedef unsigned int U32;

#pragma pack(1)
typedef struct
{
//bmp header
U16 bfType; // B M
U32 bfSize; //文件大小
U16 bfReserved1;
U16 bfReserved2;
U32 bfOffBits; //文件头偏移量

//DIB header
U32 biSize; //DIB头大小
U32 biWidth; //文件宽度
U32 biHeight; //文件高度
U16 biPlanes;
U16 biBitCount; //每个相素点的位数
U32 biCompression;
U32 biSizeImage; //图文件大小
U32 biXPelsPerMeter;
U32 biYPelsPerMeter;
U32 biClrUsed;
U32 biClrImportant;
} BMP_HEADER;
#pragma pack()

U8 Lagrange(int, int, double[], double );
void out(BMP_HEADER); // 打印bmp文件头\信息头信息
void read_Imag(char*, char*, BMP_HEADER&, U8*&);// 读取bmp文件信息
void scan_H_W_n(int&, int&, int&); // 输入目标图片的宽度、高度和插值样本点数
void change_Imag(BMP_HEADER, U8*&, U8*&, U8*, int, int, int );//修改图片信息
void write_Imag(char*, BMP_HEADER, U8*&, U8*, int, int );//将信息保存至bmp文件中

int main()
{
U8 clrPal[256*4];
int width,height,n;
U8* data, *temp;
char fName0[256],fName[256];
BMP_HEADER header;
int ok = 1, cnt=0;

while(1) {
printf("是否需要进行图片缩放?(0表示否,其它表示是):"); scanf("%d", &ok);
if(!ok) break;
read_Imag(fName0, fName, header, data);
scan_H_W_n(width, height, n);
change_Imag(header, data, temp, clrPal, width, height, n);
write_Imag(fName, header, temp, clrPal, width, height);
}

}

void scan_H_W_n(int& width, int& height, int& n){
printf("输入缩放后的宽度、高度:"); scanf("%d %d", &width, &height);
printf("输入样本点个数:"); scanf("%d", &n);
}
U8 Lagrange(int pos, int num, double x[], double g) {
double y = 0, temp;
for(int i=0;i<num;i++) {
temp = 1.0;
for(int j=pos;j<pos+num;j++)
if(j != i + pos)
temp = temp*(g-j)*1.0/(i+pos-j);
y += x[i]*temp;
}
return (U8)y;
}
void out(BMP_HEADER header){
printf(" bfType : %c%c\n", header.bfType%256,header.bfType/256 );
printf(" bfSize : %d \n", header.bfSize );
printf(" bfReserved1 : %d \n", header.bfReserved1 );
printf(" bfReserved2 : %d \n", header.bfReserved2 );
printf(" bfOffBits : %d\n\n", header.bfOffBits );
printf(" biSize : %d \n", header.biSize );
printf(" biWidth : %d \n", header.biWidth );
printf(" biHeight : %d \n", header.biHeight );
printf(" biPlanes : %d \n", header.biPlanes );
printf(" biBitCount : %d \n", header.biBitCount );
printf(" biCompression : %d \n", header.biCompression );
printf(" biSizeImage : %d \n", header.biSizeImage );
printf(" biXPelsPerMeter : %d \n", header.biXPelsPerMeter );
printf(" biYPelsPerMeter : %d \n", header.biYPelsPerMeter );
printf(" biClrUsed : %d \n", header.biClrUsed );
printf(" biClrImportant : %d \n", header.biClrImportant );
}
void read_Imag(char *fName0, char* fName, BMP_HEADER &header, U8*&data){
printf("请输入需要进行缩放图片文件名:"); scanf("%s", fName0);
printf("请输入保存缩放图片的文件名:"); scanf("%s", fName);
FILE* fp;
fp = fopen(fName0,"rb");
if(NULL == fp)
perror("open bmp file fail");
fread(&header, sizeof(BMP_HEADER), 1, fp);
out(header);
fseek(fp,header.bfOffBits,SEEK_SET);
mac(data, header.biSizeImage);
fread(data,header.biSizeImage,1,fp);
fclose(fp);

}
void change_Imag(BMP_HEADER header, U8*& data, U8*&temp, U8* clrPal,int width, int height, int n){
int lwidth, lheight, stride;
stride = header.biSizeImage / header.biHeight;
lwidth = header.biWidth;
lheight = header.biHeight;
int h = header.biBitCount/8;
mac(temp, (width*h+3)/4*4*height);
if(h==1)
{
for(int i=0; i<256; i++)
{
clrPal[4*i] = clrPal[4*i+1] = clrPal[4*i+2] = i;
clrPal[4*i+3] = 0;
}
}
double x[n+1];
if(h != 1 && h != 3);
else {
int ww = (width*h+3)/4*4;
for(int i=0, l;i<height;i++) {
int ii = (int)(1.0*i*(lheight-1)/(height-1)+0.5);
for(int j=0;j<width;j++){
double g = 1.0*j*(lwidth-1)/(width-1);
if(n&1) l = (int)(g+0.5) - n/2 ;
else l = (int)(g+0.0) - n/2 + 1;
for(int k=0;k<h;k++){
for(int r=l;r<l+n;r++)
if(r<0) x[r-l] = data[ii*stride - r*h+k];
else if(r < lwidth) x[r-l] = data[ii*stride + r*h+k];
else x[r-l] = data[ii*stride + (2*lwidth-2-r)*h+k];
temp[i*ww + j*h+k] = (U8)Lagrange(l, n, x, g);
}
}
for(int j=width*h; j<ww;j++) temp[i*ww + j] = 0;
}
}
free(data);
}


void write_Imag(char *fName, BMP_HEADER header, U8* &temp, U8* clrPal, int width, int height){
int bpp = header.biBitCount;
FILE *fp = fopen(fName, "wb+");
if(fp == NULL )
perror("open x.bmp fail");
header.biSizeImage = (width*bpp/8+3)/4*4*height;
header.bfSize = header.bfOffBits + header.biSizeImage;
header.biWidth = width;
header.biHeight = height;
puts("******缩放后bmp文件头、信息头******");
out(header);
fwrite(&header, sizeof(BMP_HEADER), 1, fp);
if(bpp == 8) fwrite(clrPal, 1024, 1, fp);
fwrite(temp, header.biSizeImage, 1, fp);
fclose(fp);
free(temp);
puts("图片缩放成功!\n");
}