C语言实现二值图像模拟灰值图像显示效果(图案法、抖动法)

图案法

图案法(patterning)是指灰度可以用一定比例的黑白点组成的区域表示,从而达到整体图象的灰度感。黑白点的位置选择称为图案化。

下面介绍的一种设计标准图案的算法,是由Limb在1969年提出的。
先以一个2×2的矩阵开始:

在这里插入图片描述通过递归关系有:
在这里插入图片描述其中Mn和Un均为2n×2n的方阵,Un的所有元素都是1。
根据这个算法M2如下,为16级灰度的标准图案:

在这里插入图片描述M3(8×8阵)比较特殊,称为Bayer抖动表。M4是一个16×16的矩阵。

M3 表模拟灰值图像显示效果:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#pragma pack(1)   //全紧凑模式

typedef struct {
	unsigned char bfType[2];
	unsigned long bfSize;
	unsigned short bfReserved1;
	unsigned short bfReserved2;
	unsigned long bfOffBits;
}bitmapFileHeader;

typedef struct {
	unsigned long biSize;
	unsigned long biWidth;
	unsigned long biHeight;
	unsigned short biPlanes;
	unsigned short biBitCount;
	unsigned long biCompression;
	unsigned long biSizeImage;
	long biXPixPerMeter;
	long biYPixPerMeter;
	unsigned long biClrUsed;
	unsigned long biClrImportant;
}bitmapInfoHeader;


typedef struct{
	unsigned char rgbBlue;
	unsigned char rgbGreen;
	unsigned char rgbRed;
	unsigned char rgbReserved;

}rgbQUAD;

typedef struct{
	bitmapFileHeader bfHeader;
	bitmapInfoHeader biHeader;
	rgbQUAD palette[256];
	unsigned char *imgData;
}bmp;

int main(){
	FILE *fp;
	if((fp=fopen("d:\Temp\\test_gray.bmp","rb"))==NULL){
		perror("can not open file!");
		return -1;
	}
	//读入彩色bmp图像文件头,信息头和图像数据
	bitmapFileHeader bfHeader;
	fread(&bfHeader,14,1,fp);
	bitmapInfoHeader biHeader;
	fread(&biHeader,40,1,fp);
	int imSize=biHeader.biSizeImage;
	int width=biHeader.biWidth;
	int height=biHeader.biHeight;
	int bitCount=biHeader.biBitCount;
	int lineBytes=(width*bitCount+31)/32*4;
	
	fseek(fp,bfHeader.bfOffBits,SEEK_SET);
	unsigned char*imageData=(unsigned char*)malloc(imSize*sizeof(unsigned char));
	fread(imageData,imSize*sizeof(unsigned char),1,fp);	
	fclose(fp);

	bmp b;
	memcpy(&(b.bfHeader),&bfHeader,sizeof(bfHeader));
	memcpy(&(b.biHeader),&biHeader,sizeof(biHeader));
	b.imgData=(unsigned char*)malloc(sizeof(unsigned char)*imSize);
	memset(b.imgData,0,sizeof(unsigned char)*imSize);
	for(int i=0;i<256;i++){
		b.palette[i].rgbBlue=i;
		b.palette[i].rgbGreen=i;
		b.palette[i].rgbRed=i;
	}
	
	int i,j,temp;
	unsigned char bayer[8][8]={  
		0,32,8,40,2,34,10,42,
		48,16,56,24,50,18,58,26,
		12,44,4,36,14,46,6,38,
		60,28,52,20,62,30,54,22,
		3,35,11,43,1,33,9,41,
        51,19,59,27,49,17,57,25,
		15,47,7,39,13,45,5,37,
        63,31,55,23,61,29,53,21
	};
	for(i=0;i<height;i++){ 
		for(j=0;j<width;j++){ 
			temp=imageData[lineBytes*i+j];
			if((temp>>2)>bayer[i&7][j&7])
				b.imgData[lineBytes*i+j]=255;
			else
				b.imgData[lineBytes*i+j]=0;
		}
	}
	
	char savePath[]="D:\Temp\\save_test.bmp";
	FILE *f_save=fopen(savePath,"wb");
	if(f_save==NULL){
		perror("can not open file!");
		return -2;
	}

	fwrite(&b.bfHeader,sizeof(bitmapFileHeader),1,f_save);
	fwrite(&b.biHeader,sizeof(bitmapInfoHeader),1,f_save);
	fwrite(&b.palette,1024,1,f_save);
	fwrite(b.imgData,sizeof(unsigned char)*b.biHeader.biSizeImage,1,f_save);
	fclose(f_save);
	
	free(imageData);
	free(b.imgData);
	getchar();
	return 0;
}


代码效果:

在这里插入图片描述

抖动法

假设灰度级别的范围从b(black)到w(white),中间值t为(b+w)/2,对应256级灰度,b=0,w=255,t=127.5。设原图中象素的灰度为g,误差值为e,则新图中对应象素的值用如下的方法得到:

    if g > t then
		打白点
		e=g-w
	else 
		打黑点
		e=g-b
	3/8 × e 加到右边的象素
	3/8 × e 加到上边的象素
	1/4 × e 加到右上方的象素

实现代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#pragma pack(1)   //全紧凑模式

typedef struct {
	unsigned char bfType[2];
	unsigned long bfSize;
	unsigned short bfReserved1;
	unsigned short bfReserved2;
	unsigned long bfOffBits;
}bitmapFileHeader;

typedef struct {
	unsigned long biSize;
	unsigned long biWidth;
	unsigned long biHeight;
	unsigned short biPlanes;
	unsigned short biBitCount;
	unsigned long biCompression;
	unsigned long biSizeImage;
	long biXPixPerMeter;
	long biYPixPerMeter;
	unsigned long biClrUsed;
	unsigned long biClrImportant;
}bitmapInfoHeader;


typedef struct{
	unsigned char rgbBlue;
	unsigned char rgbGreen;
	unsigned char rgbRed;
	unsigned char rgbReserved;

}rgbQUAD;

typedef struct{
	bitmapFileHeader bfHeader;
	bitmapInfoHeader biHeader;
	rgbQUAD palette[256];
	unsigned char *imgData;
}bmp;

int main(){
	FILE *fp;
	if((fp=fopen("d:\Temp\\test_gray.bmp","rb"))==NULL){
		perror("can not open file!");
		return -1;
	}
	//读入彩色bmp图像文件头,信息头和图像数据
	bitmapFileHeader bfHeader;
	fread(&bfHeader,14,1,fp);
	bitmapInfoHeader biHeader;
	fread(&biHeader,40,1,fp);
	int imSize=biHeader.biSizeImage;
	int width=biHeader.biWidth;
	int height=biHeader.biHeight;
	int bitCount=biHeader.biBitCount;
	int lineBytes=(width*bitCount+31)/32*4;
	
	fseek(fp,bfHeader.bfOffBits,SEEK_SET);
	unsigned char*imageData=(unsigned char*)malloc(imSize*sizeof(unsigned char));
	fread(imageData,imSize*sizeof(unsigned char),1,fp);	
	fclose(fp);

	bmp b;
	memcpy(&(b.bfHeader),&bfHeader,sizeof(bfHeader));
	memcpy(&(b.biHeader),&biHeader,sizeof(biHeader));
	b.imgData=(unsigned char*)malloc(sizeof(unsigned char)*imSize);
	memset(b.imgData,0,sizeof(unsigned char)*imSize);
	for(int i=0;i<256;i++){
		b.palette[i].rgbBlue=i;
		b.palette[i].rgbGreen=i;
		b.palette[i].rgbRed=i;
	}
	
	int i,j,temp;
	double e,f;
	for(i=0;i<height;i++){
		for(j=0;j<width;j++){
			b.imgData[lineBytes*i+j]=imageData[lineBytes*i+j]; //拷贝数据
		}
	}
	
	for(i=0;i<height;i++){ 
		for(j=0;j<width;j++){ 
			temp=b.imgData[lineBytes*i+j];
			if(temp>128){
				b.imgData[lineBytes*i+j]=255;
				e=(float)(temp-255);
			}
			else{
				b.imgData[lineBytes*i+j]=0;
				e=(float)temp;
			}
			if(j<width-1){
				f=b.imgData[lineBytes*i+j+1];
				f+=3.0/8.0*e;
				b.imgData[lineBytes*i+j+1]=(unsigned char)f; //向右传播
			}
			if(i<height-1){
				f=b.imgData[lineBytes*(i+1)+j];
				f+=3.0/8.0*e;
				b.imgData[lineBytes*(i+1)+j]=(unsigned char)f; //向上传播
				f=b.imgData[lineBytes*(i+1)+j+1];
				f+=1.0/4.0*e;
				b.imgData[lineBytes*(i+1)+j+1]=(unsigned char)f; //向右上传播
			}
		}
	}
	
	
	char savePath[]="D:\Temp\\save_test.bmp";
	FILE *f_save=fopen(savePath,"wb");
	if(f_save==NULL){
		perror("can not open file!");
		return -2;
	}

	fwrite(&b.bfHeader,sizeof(bitmapFileHeader),1,f_save);
	fwrite(&b.biHeader,sizeof(bitmapInfoHeader),1,f_save);
	fwrite(&b.palette,1024,1,f_save);
	fwrite(b.imgData,sizeof(unsigned char)*b.biHeader.biSizeImage,1,f_save);
	fclose(f_save);
	
	free(imageData);
	free(b.imgData);
	getchar();
	return 0;
}


代码效果:

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值