用程序读入BMP的信息,将该信息重新写出生成图片时,图片右侧一小部分移到了图片的左侧。请各位帮我看看问题出在哪,帮帮我,谢谢!
代码如下:
```c++
typedef struct {
BITMAP bmp; // BITMAP構造体
RGBQUAD *rgb ;
} BMPDATA;
bool ReadBmp(string strbmpName, int & m_nBiBitCount)
{
FILE *fp = new FILE;
int resOpen = fopen_s(&fp, strbmpName.c_str(), "rb");
if (resOpen)
{
return false;
}
fseek(fp, sizeof(BITMAPFILEHEADER), 0);
//BITMAPFILEHEADER filehead;
//fread(&filehead, 1, sizeof(BITMAPFILEHEADER), fp);
BMPDATA* m_pBitmapData = new BMPDATA;
BITMAPINFOHEADER bitmapInfoHeader;
//定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中
fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp); //获取图像宽、高、每像素所占位数等信息
m_nBiBitCount = bitmapInfoHeader.biBitCount;//定义变量,计算图像每行像素所占的字节数(必须是4的倍数)
m_pBitmapData->bmp.bmType = 0;
m_pBitmapData->bmp.bmWidth = bitmapInfoHeader.biWidth;
m_pBitmapData->bmp.bmHeight = bitmapInfoHeader.biHeight;
int lineByte = (m_pBitmapData->bmp.bmWidth * m_nBiBitCount / 8 + 3) / 4 * 4;//灰度图像有颜色表,且颜色表表项为256
//int lineByte = ((((m_pBitmapData->bmp.bmWidth * m_nBiBitCount) + 31) & ~31) >> 3);
m_pBitmapData->bmp.bmWidthBytes = lineByte;
m_pBitmapData->bmp.bmPlanes = bitmapInfoHeader.biPlanes; //颜色平面数
m_pBitmapData->bmp.bmBitsPixel = bitmapInfoHeader.biBitCount;
if (m_nBiBitCount == 8)
{
//申请颜色表所需要的空间,读颜色表进内存
RGBQUAD *pQuad = new RGBQUAD[256];
fread(pQuad, sizeof(RGBQUAD), COLOR_TABLE_ENTRIES, fp);
m_pBitmapData->rgb = pQuad;
}
m_pBitmapData->bmp.bmBits = new unsigned char[lineByte * m_pBitmapData->bmp.bmHeight];
fread(m_pBitmapData->bmp.bmBits, sizeof(UCHAR), lineByte * m_pBitmapData->bmp.bmHeight, fp);
fclose(fp);//关闭文件
return true;
}
bool SaveBmp(string strBmpName, BMPDATA *m_pBitmapData, int m_nBiBitCount)
{
//如果位图数据指针为0,则没有数据传入,函数返回
if (m_pBitmapData == NULL)
{
return false;
}
if (!m_pBitmapData->bmp.bmBits)
{
return false;
}
//颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0
int colorTablesize = 0;
if (m_nBiBitCount == 8)
{
colorTablesize = 1024;
}
//以二进制写的方式打开文件
FILE *fp = new FILE;
int resOpen = fopen_s(&fp, strBmpName.c_str(), "wb");
if (resOpen)
{
return false;
}
//申请位图文件头结构变量,填写文件头信息
BITMAPFILEHEADER fileHead;
fileHead.bfType = 0x4D42;//bmp类型
//bfSize是图像文件4个组成部分之和
fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize +
m_pBitmapData->bmp.bmWidthBytes * m_pBitmapData->bmp.bmHeight;
fileHead.bfReserved1 = 0;
fileHead.bfReserved2 = 0;
//bfOffBits是图像文件前3个部分所需空间之和
fileHead.bfOffBits = 54 + colorTablesize;
//写文件头进文件
fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp);
//申请位图信息头结构变量,填写信息头信息
BITMAPINFOHEADER infohead;
infohead.biBitCount = m_nBiBitCount;
infohead.biClrImportant = 0;
infohead.biClrUsed = 0;
infohead.biCompression = 0;
infohead.biHeight = m_pBitmapData->bmp.bmHeight;
infohead.biPlanes = 1;
infohead.biSize = 40;
infohead.biSizeImage = m_pBitmapData->bmp.bmWidthBytes * sizeof(RGBTRIPLE) * abs(m_pBitmapData->bmp.bmHeight);
infohead.biWidth = m_pBitmapData->bmp.bmWidth;
infohead.biXPelsPerMeter = 0;
infohead.biYPelsPerMeter = 0;
//写位图信息头进内存
fwrite(&infohead, sizeof(BITMAPINFOHEADER), 1, fp);
//如果灰度图像,有颜色表,写入文件
if (m_nBiBitCount == 8 && m_pBitmapData->rgb)
{
fwrite(m_pBitmapData->rgb, sizeof(RGBQUAD), COLOR_TABLE_ENTRIES, fp);
}
//写位图数据进文件
fwrite(m_pBitmapData->bmp.bmBits, m_pBitmapData->bmp.bmHeight * m_pBitmapData->bmp.bmWidthBytes, 1, fp);
//关闭文件
fclose(fp);
return true;
}
```
bmp.h
# ifndef BMP_H
# define BMP_H
/*位图文件头*/
#pragma pack(1)//单字节对齐
typedef struct tagBITMAPFILEHEADER
{
unsigned char bfType[2]; //文件格式
unsigned int bfSize; // 文件大小 以字节为单位(2-5字节)
unsigned short bfReserved1; // 保留,必须设置为0 (6-7字节)
unsigned short bfReserved2; // 保留,必须设置为0 (8-9字节)
unsigned int bfOffBits; // 从文件头到像素数据的偏移 (10-13字节)
}BITMAPFILEHEADER;
#pragma pack()
/*位图信息头*/
#pragma pack(1)
typedef struct tagBITMAPINFOHEADER
{
unsigned int biSize; // 此结构体的大小 (14-17字节)
long biWidth; // 图像的宽 (18-21字节)
long biHeight; // 图像的高 (22-25字节)
unsigned short biPlanes; // 表示bmp图片的平面属,显然显示器只有一个平面,所以恒等于1 (26-27字节)
unsigned short biBitCount; // 一像素所占的位数,(28-29字节)当biBitCount=24时,该BMP图像就是24Bit真彩图,没有调色板项。
unsigned int biCompression; // 说明图象数据压缩的类型,0为不压缩。(30-33字节)
unsigned int biSizeImage; // 像素数据所占大小, 这个值应该等于上面文件头结构中bfSize-bfOffBits (34-37字节)
long biXPelsPerMeter; // 说明水平分辨率,用象素/米表示。一般为0 (38-41字节)
long biYPelsPerMeter; // 说明垂直分辨率,用象素/米表示。一般为0 (42-45字节)
unsigned int biClrUsed; // 说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项)。(46-49字节)
unsigned int biClrImportant; // 说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。(50-53字节)
}BITMAPINFOHEADER;
#pragma pack()
/*调色板结构*/
#pragma pack(1)
typedef struct tagRGBQUAD
{
unsigned char rgbBlue; //该颜色的蓝色分量 (值范围为0-255)
unsigned char rgbGreen; //该颜色的绿色分量 (值范围为0-255)
unsigned char rgbRed; //该颜色的红色分量 (值范围为0-255)
unsigned char rgbReserved;// 保留,必须为0
}RGBQUAD;
#pragma pack()
#endif
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include"bmp.h"
//#define DEBUG //没注释 是图像处理前16 二值化后的图像8位 注释了 是图像处理前和处理后 图像深度16位
int main()
{
/*变量声明*/
FILE *fpBMP,*fpTwoValue;//源文件fpBMP,目标文件fpTwoValue
char filename1[20], filename2[20];
BITMAPFILEHEADER *fileHeader;//位图文件头
BITMAPINFOHEADER *infoHeader;//位图信息头
#ifdef DEBUG
RGBQUAD *ipRGB;//调色板 读入的图片为16位 和 保存的图像为16位不需要调色板
#endif
int i,j;
unsigned char *a;//存储源图每行像素值
unsigned char *c;//存储每行像素的二值
printf("输入图像文件名:");
scanf("%s", filename1);
if ((fpBMP = fopen(filename1, "rb")) == NULL)
{
printf("打开图片失败");
exit(0);
}
printf("输出图像文件名:");
scanf("%s", filename2);
if ((fpTwoValue = fopen(filename2, "wb")) == NULL)
{
printf("创建图片失败");
exit(0);
}
/********************************************************************/
/*创建位图文件头,信息头,调色板*/
fileHeader=(BITMAPFILEHEADER *)malloc(sizeof(BITMAPFILEHEADER));
infoHeader=(BITMAPINFOHEADER *)malloc(sizeof(BITMAPINFOHEADER));
#ifdef DEBUG
ipRGB=(RGBQUAD *)malloc(2*sizeof(RGBQUAD));
#endif
/*读入源位图文件头和信息头*/
fread(fileHeader,sizeof(BITMAPFILEHEADER),1,fpBMP);
fread(infoHeader,sizeof(BITMAPINFOHEADER),1,fpBMP);
//经过这两条程序把BMP图像的信息头、文件头赋给fileHeader和infoHeader变量,可以根据fileHeader和infoHeader得到图像的各种属性。
printf("原始图片每个像素的位数:%d\n" ,infoHeader->biBitCount);
printf("原始图片每个像素像素数据偏移:%d\n" ,fileHeader->bfOffBits);
#ifdef DEBUG
//修改信息头
//信息头共有11部分,灰度化时需要修改4部分 这里位深度是16且没有变 只需要改2部分
infoHeader->biBitCount=8;//转换成二值图后,颜色深度由16位变为8位
infoHeader->biSizeImage=((infoHeader->biWidth*1+3)/4)*4*infoHeader->biHeight;//每个像素由2字节变为1字节,同时每行像素要四字节对齐
infoHeader->biClrUsed=2;//颜色索引表数量,二值图为2
infoHeader->biClrImportant=0;//重要颜色索引为0,表示都重要
#else
//修改信息头
//信息头共有11部分,灰度化时需要修改4部分 这里位深度是16且没有变 只需要改2部分
//infoHeader->biBitCount=8;//转换成二值图后,颜色深度由16位变为8位
//infoHeader->biSizeImage=((infoHeader->biWidth*1+3)/4)*4*infoHeader->biHeight;//每个像素由2字节变为1字节,同时每行像素要四字节对齐
infoHeader->biClrUsed=2;//颜色索引表数量,二值图为2
infoHeader->biClrImportant=0;//重要颜色索引为0,表示都重要
#endif
#ifdef DEBUG
//修改文件头
//文件头共有5部分,灰度化时需要修改5部分 用到调色板
fileHeader->bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+2*sizeof(RGBQUAD);//数据区偏移量,等于文件头,信息头,索引表的大小之和
fileHeader->bfSize=fileHeader->bfOffBits+infoHeader->biSizeImage;//文件大小,等于偏移量加上数据区大小
ipRGB[0].rgbBlue=ipRGB[0].rgbGreen=ipRGB[0].rgbRed=ipRGB[0].rgbReserved=255; //白色对应的索引为150-255
ipRGB[1].rgbBlue=ipRGB[1].rgbGreen=ipRGB[1].rgbRed=ipRGB[1].rgbReserved=0;//调色板颜色为黑色对应的索引为0
#else
//修改文件头
//文件头共有5部分,灰度化时需要修改1部分 没有用到调色板
fileHeader->bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);//数据区偏移量,等于文件头,信息头,索引表的大小之和
#endif
printf("修改后的图片每个像素的位数:%d\n" ,infoHeader->biBitCount);
printf("修改后的图片每个像素数据偏移:%d\n" ,fileHeader->bfOffBits);
/********************************************************************/
//读取BMP图像的信息头、文件头、BMP调色板到新建的图片
fwrite(fileHeader,sizeof(BITMAPFILEHEADER),1,fpTwoValue);
fwrite(infoHeader,sizeof(BITMAPINFOHEADER),1,fpTwoValue);
#ifdef DEBUG
fwrite(ipRGB,2*sizeof(RGBQUAD),1,fpTwoValue);
#endif
/*将彩色图转为二值图*/
// (infoHeader->biWidth*biBitCount+31)/8/4*4
// 这里 biBitCount = 16 表达式 (infoHeader->biWidth*16+31)/8/4*4
// 化简后 (infoHeader->biWidth*2+3)/4*4 用的是数学上的取整操作
a=(unsigned char *)malloc((infoHeader->biWidth*2+3)/4*4);//给变量a申请源图每行像素所占大小的空间,考虑四字节对齐问题
#ifdef DEBUG
c=(unsigned char *)malloc((infoHeader->biWidth*1+3)/4*4);//给变量c申请目标图每行像素所占大小的空间,同样四字节对齐
#else
c=(unsigned char *)malloc((infoHeader->biWidth*2+3)/4*4);//给变量c申请目标图每行像素所占大小的空间,同样四字节对齐
#endif
for(i=0;i<infoHeader->biHeight;i++)//遍历图像每行的循环
{
for(j=0;j<((infoHeader->biWidth*2+3)/4*4);j++)//遍历每行中每个字节的循环
{
fread(a+j,1,1,fpBMP);//将源图每行的每一个字节读入变量a所指向的内存空间
}
#ifdef DEBUG
for(j=0;j<(infoHeader->biWidth*1);j++)//循环像素宽度次,就不会计算读入四字节填充位
#else
for(j=0;j<(infoHeader->biWidth*2);j++)//循环像素宽度次,就不会计算读入四字节填充位
#endif
{
#ifdef DEBUG
//白色为RGB分量都有
//r = pixel & 0xf800
//g = pixel & 0x07e0
//b = pixel & 0x1f
if(100<=(a[j*2+1] & 0xf8)) //将灰度值转化为二值 这里由于白色含有红绿蓝 ,所以选取其中一个分量比较 ,大于就是255 小于就是0
c[j]=0;
else
c[j]=255;
#else
if(j%2==0)
{
if(100<=(a[j+1] & 0xf8)) //将灰度值转化为二值,这里选取的阈值为160-190都可以
c[j]=255;
else
c[j]=0;
}
else
c[j] = c[j-1]; //存储每行的二值
#endif
}
#ifdef DEBUG
fwrite(c,(infoHeader->biWidth*1+3)/4*4,1,fpTwoValue);//将二值像素4字节填充写入文件,填充位没有初始化,为随机值
#else
fwrite(c,(infoHeader->biWidth*2+3)/4*4,1,fpTwoValue);//将二值像素四字节填充写入文件,填充位没有初始化,为随机值
#endif
}
/*释放内存空间,关闭文件*/
free(fileHeader);
free(infoHeader);
// free(ipRGB);
free(a);
free(c);
fclose(fpBMP);
fclose(fpTwoValue);
printf("bmp图片背景去除完成\n");
return 0;
}
我需要您提供代码,以便更好地了解您的问题和提供解决方案。由参考资料可以了解到BMP图片格式的组成,但是无法确定具体是哪里出现了偏移,也无法确定代码中的问题,因此无法提供具体的解决方案。请提供您的代码,谢谢。