MFC数字图像处理24位图转8位图 等四种图像色彩转换方式
2016-10-25 11:08
1081 查看
一、 实验主要思路和基本操作
本实验主要探究8位图和24位图的颜色转换。8位图具有调色板,调色板中有对应的256种不同的颜色,每种颜色所含的RGB值都不一样。24位图没有调色板,RGB三个颜色分量分别都有0-255可选择,属于真彩色图像。其中,两种不同位数的图形都有彩色图像和灰度图像两种,灰度图像中每个像素的颜色分量,R、G、值都一样。所以本实验核心分为两点:了解颜色的RGB组合和学会调色板的使用
调色板:
主要功能是节省图像字节。8位图像中,图中最多256中颜色,如果采用颜色表,表中每一行记录一种颜色的RGB值,当表示一个像素颜色时,只需要指出该颜色是在第几行,即该颜色在表中的索引值就可以。如,表第0行是255,0,0,为红色时,只需要标明0即可。通过颜色表来表示图像,256种颜色可以用8位表示,一个像素使用1个字节,比原来的每个像素使用3个字节(256+256+256,每个分量一个字节表示)节省很大空间。
24位图由于每个分量中0-255个值都有可能用到,使用调色板反而会增加3个字节的使用调色板空间。所以24位图不使用调色板。
RGB组合:彩色图像三个RGB分量不一定相同,灰色图像三个RGB值相同。0-255的颜色分量可表示各灰度像素的亮度。
基本操作:1.在资源视图中的菜单选项,建立操作菜单,并对菜单定义相应ID。
2.在类视图-属性-事件中,为菜单添加触发操作。
3.在VIEW类中编写程序。
(注:本文所有实验结果图因为无法复制粘贴,重新生成图片较为麻烦,次实验也做较久,故不贴图片显示实验结果。之后实时做的实验都会贴图,望理解。)
二、主要程序
一、8位彩色转换成8位灰度
1.原理:获取原图信息,新建一个调色板,找到该图像对应的像素值,计算该颜色对应的灰度值,通过逐行扫描更换每个像素的颜色索引,更新并保存图像。
细节:1.首先通过lpSrcColorBits=lpSrcDib+sizeof(BITMAPINFOHEADER)获取调色板的指针信息。在新建立的调色板中,利用获取的原图像调色板计算该像素点对应的灰度值。调色板的每一行有3个字节,于是以3为周期,对调色板各个像素信息进行更新。
2.进行逐行扫描时,通过指针先找到数据起始点,逐行对每一行每一列的像素值进行更新。
3.定义像素信息的指针用LPSTR类型。
2.代码实现
3.实验结果
二、24彩色位转24位灰度
1.原理:24位彩色图没有颜色表,所以仅需通过获取位图信息,找到像素点的RGB数据,对像素点进行灰度计算,更新图像,就能完成转换。
细节:1.像素的颜色分量为unsigned char类型。
2.代码实现
3.实验结果
三、24位彩色转8位灰度
1.原理:申请位图数据所需要的空间,将新图像位数改为8位,建立新的调色板,申请颜色表需要的空间,给颜色表赋值,逐行扫描,对各像素点进行灰度变换,更新图像。
细节:1.申请新图像时,对图像位数进行更改。
2.颜色表的定义 RGBQUAD* pColorTable
2.代码实现
3.实验结果
四、24位彩色转8位彩色
1.原理:1.建立八叉树,合并子树。将拥有256*256*256色的真彩色图像,转换为256色图像。八叉树节点的特性就是每个节点最多有8个字节点,编号为0~7 。以RGB值建立八叉树,首先建立根节点,然后分别以RGB的每一位分别组成一个0~7的值,依次插入树中。以RGB(123,54,78)为例。
以此类推,将所有的RGB值逐层插入到八叉树中,在每个节点上,记录所有经过的节点的RGB值的总和,以及RGB颜色个数。插入的过程中,如果节点不存在,则需要创建新的节点,然后增加节点计数以及RGB各分量的总和.当在插入时,发现节点已经存在,且是叶子节点,则停止该颜色后续层数节点的插入。插入完一个颜色之后,如果叶子节点数超过了我们要得到的颜色数(256色需要得到256种颜色),这时候就需要合并一些呀字节点了,使的叶子节点的个数不超过我们要得到的颜色数。
由于越底层的节点,数据的敏感度越低,所以,我们将从最底层的节点开始合并。按节点计数值小的优先合并策略,将其字节点的所有RGB分量以及节点计数全部记录到该节点中,并删除其所有子节点。依此进行,直到合并后的叶子数符合要求为止。
2.提取调色板 按照上述的步骤插入完所有的颜色之后,便建立起一颗叶子节点不超过256的八叉树。此时,取出叶子节点中的RGB分量的平均值(分量总和 / 节点计数),即是得到的调色板颜色值。
3.匹配调色板索引 所谓匹配调色板索引,就是根据原始的RGB值,在调色板中查找出最接近的颜色的索引。对每个RGB颜色,分别对调色板数据求各分量的差值的平方和,求的的最小值对应的调色板颜色的索引,即是该RGB颜色匹配到的调色板索引。
细节:1.定义直接插入排序(sort1)和快速排序(sort2)两种排序方式,通过两种排序方式,建立八叉树。计算各个像素值的使用频率,将使用最高的前256种,定义为调色板。其中usedTimes数组中是各颜色使用频率。并用原来的useTimes数组来保存索引值
2.用PFC函数计算,当像素值不在颜色表256位时,寻找这256种中最接近的颜色。
代码实现
本实验主要探究8位图和24位图的颜色转换。8位图具有调色板,调色板中有对应的256种不同的颜色,每种颜色所含的RGB值都不一样。24位图没有调色板,RGB三个颜色分量分别都有0-255可选择,属于真彩色图像。其中,两种不同位数的图形都有彩色图像和灰度图像两种,灰度图像中每个像素的颜色分量,R、G、值都一样。所以本实验核心分为两点:了解颜色的RGB组合和学会调色板的使用
调色板:
主要功能是节省图像字节。8位图像中,图中最多256中颜色,如果采用颜色表,表中每一行记录一种颜色的RGB值,当表示一个像素颜色时,只需要指出该颜色是在第几行,即该颜色在表中的索引值就可以。如,表第0行是255,0,0,为红色时,只需要标明0即可。通过颜色表来表示图像,256种颜色可以用8位表示,一个像素使用1个字节,比原来的每个像素使用3个字节(256+256+256,每个分量一个字节表示)节省很大空间。
24位图由于每个分量中0-255个值都有可能用到,使用调色板反而会增加3个字节的使用调色板空间。所以24位图不使用调色板。
RGB组合:彩色图像三个RGB分量不一定相同,灰色图像三个RGB值相同。0-255的颜色分量可表示各灰度像素的亮度。
基本操作:1.在资源视图中的菜单选项,建立操作菜单,并对菜单定义相应ID。
2.在类视图-属性-事件中,为菜单添加触发操作。
3.在VIEW类中编写程序。
(注:本文所有实验结果图因为无法复制粘贴,重新生成图片较为麻烦,次实验也做较久,故不贴图片显示实验结果。之后实时做的实验都会贴图,望理解。)
二、主要程序
一、8位彩色转换成8位灰度
1.原理:获取原图信息,新建一个调色板,找到该图像对应的像素值,计算该颜色对应的灰度值,通过逐行扫描更换每个像素的颜色索引,更新并保存图像。
细节:1.首先通过lpSrcColorBits=lpSrcDib+sizeof(BITMAPINFOHEADER)获取调色板的指针信息。在新建立的调色板中,利用获取的原图像调色板计算该像素点对应的灰度值。调色板的每一行有3个字节,于是以3为周期,对调色板各个像素信息进行更新。
2.进行逐行扫描时,通过指针先找到数据起始点,逐行对每一行每一列的像素值进行更新。
3.定义像素信息的指针用LPSTR类型。
2.代码实现
//8位彩色转灰度------------------------------------------------------------------------------ void CImgtestView::On88grey() { CImgtestDoc* pDoc=GetDocument(); long lSrcLineBytes; long lSrcWidth; long lSrcHeight; int lpSrcBitCount; LPSTR lpSrcDib;//指向源图像的指针 LPSTR lpSrcStartBits;//指向数据的指针 lpSrcDib=(LPSTR)::GlobalLock((HGLOBAL)pDoc->GetHObject()); if(!lpSrcDib) return; if(pDoc->m_dib.GetColorNum(lpSrcDib)!=256) { AfxMessageBox(L"对不起,不是256色图!"); ::GlobalUnlock((HGLOBAL)pDoc->GetHObject()); return; } lpSrcStartBits=pDoc->m_dib.GetBits(lpSrcDib); lSrcWidth=pDoc->m_dib.GetWidth(lpSrcDib); lSrcHeight=pDoc->m_dib.GetHeight(lpSrcDib); lSrcLineBytes=pDoc->m_dib.GetReqByteWidth(lSrcWidth*8); lpSrcBitCount=pDoc->m_dib.GetBitCount(lpSrcDib); ///////////////////////////////////////////////////////// BYTE bMap[256];//灰度映射表 printf("\n对256色彩色图像变为256级灰度图像\n"); LPSTR lpSrcColorBits;//指向调色板的指针 LPSTR lpSrc;// 指向DIB第i行,第j个象素的指针 lpSrcColorBits=lpSrcDib+sizeof(BITMAPINFOHEADER); for(int i=0;i<256;i++)//生成新的调色板,并转换灰度 { // 计算该颜色对应的灰度值g=0.299*r+0.587*g+0.114*b int j=0; bMap[i]=(BYTE)(0.299 * lpSrcColorBits[j] + 0.587 * lpSrcColorBits[j+1] + 0.114 * lpSrcColorBits[j+2] + 0.5); lpSrcColorBits[j]= lpSrcColorBits[j+1]= lpSrcColorBits[j+2]= i; lpSrcColorBits=lpSrcColorBits+4; } // 更换每个象素的颜色索引(即按照灰度映射表换成灰度值) // 逐行扫描 for(int i = 0; i < lSrcHeight; i++) { //逐列扫描 for(int j = 0; j < lSrcWidth; j++) { lpSrc = lpSrcStartBits + lSrcLineBytes * (lSrcHeight - 1 - i) + j; *lpSrc =bMap[*lpSrc];// 变换 } } pDoc->SetModifiedFlag(TRUE); pDoc->UpdateAllViews(NULL); ::GlobalUnlock((HGLOBAL)pDoc->GetHObject()); }
3.实验结果
二、24彩色位转24位灰度
1.原理:24位彩色图没有颜色表,所以仅需通过获取位图信息,找到像素点的RGB数据,对像素点进行灰度计算,更新图像,就能完成转换。
细节:1.像素的颜色分量为unsigned char类型。
2.代码实现
//24 4000 位转24位灰度------------------------------------------------------------------------------ void CImgtestView::On2424grey() { // TODO: 在此添加命令处理程序代码 CImgtestDoc* pDoc=GetDocument(); long lSrcLineBytes; long lSrcWidth; long lSrcHeight; int lpSrcBitCount; LPSTR lpSrcDib;//指向源图像的指针 LPBYTE lpSrcStartBits;//指向数据的指针 lpSrcDib=(LPSTR)::GlobalLock((HGLOBAL)pDoc->GetHObject()); if(!lpSrcDib) return; lpSrcStartBits=(LPBYTE)pDoc->m_dib.GetBits(lpSrcDib); lSrcWidth=pDoc->m_dib.GetWidth(lpSrcDib); lSrcHeight=pDoc->m_dib.GetHeight(lpSrcDib); lSrcLineBytes=pDoc->m_dib.GetReqByteWidth(lSrcWidth*24); lpSrcBitCount=pDoc->m_dib.GetBitCount(lpSrcDib); ///////////////////////////////////////////////////// if (lpSrcBitCount !=24)// 判断是否是8-bpp位图 { AfxMessageBox(L"对不起,不是24位图!");// 警告 ::GlobalUnlock((HGLOBAL) pDoc->GetHObject());// 解除锁定 return; //返回 } LPSTR lpSrcColorBits;//指向调色板的指针 LPSTR lpSrc;// 指向DIB第i行,第j个象素的指针 lpSrcColorBits=lpSrcDib+sizeof(BITMAPINFOHEADER); unsigned char Intensity; unsigned char *lpR,*lpB,*lpG; for(int y=0;y<lSrcHeight;y++) { for(int x=0;x<lSrcWidth;x++) { lpR = lpSrcStartBits + lSrcLineBytes * (lSrcHeight - 1 - y) + x*3; lpB = lpSrcStartBits + lSrcLineBytes * (lSrcHeight - 1 - y) + x*3+1; lpG = lpSrcStartBits + lSrcLineBytes * (lSrcHeight - 1 - y) + x*3+2; Intensity=0.299 *(* lpR) + 0.587 *(* lpB) + 0.114 * (*lpG ); if(Intensity>255) Intensity=255; if(Intensity<0) Intensity=0; *lpR= *lpB= *lpG= Intensity; } } pDoc->SetModifiedFlag(TRUE); pDoc->UpdateAllViews(NULL); ::GlobalUnlock((HGLOBAL)pDoc->GetHObject()); }
3.实验结果
三、24位彩色转8位灰度
1.原理:申请位图数据所需要的空间,将新图像位数改为8位,建立新的调色板,申请颜色表需要的空间,给颜色表赋值,逐行扫描,对各像素点进行灰度变换,更新图像。
细节:1.申请新图像时,对图像位数进行更改。
2.颜色表的定义 RGBQUAD* pColorTable
2.代码实现
//24位转8位灰度------------------------------------------------------------------------------ void CImgtestView::On248grey() { // TODO: 在此添加命令处理程序代码 CImgtestDoc* pDoc=GetDocument(); long lSrcLineBytes; //图象每行的字节数 long lSrcWidth; //图象的宽度和高度 long lSrcHeight; int lpSrcBitCount; //图像的位深 LPSTR lpSrcDib; //指向源图象的指针 LPSTR lpSrcStartBits; //指向源像素的指针 lpSrcDib= (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHObject());// 锁定DIB if (!lpSrcDib) return; if (pDoc->m_dib.GetBitCount(lpSrcDib) != 24)// 判断是否是24-bpp位图 { AfxMessageBox(L"对不起,不是24位图!");// 警告 ::GlobalUnlock((HGLOBAL) pDoc->GetHObject());// 解除锁定 return; //返回 } lpSrcStartBits=pDoc->m_dib.GetBits(lpSrcDib); // 找到DIB图象像素起始位置 lSrcWidth= pDoc->m_dib.GetWidth(lpSrcDib); // 获取图象的宽度 lSrcHeight= pDoc->m_dib.GetHeight(lpSrcDib); // 获取图象的高度 lpSrcBitCount=pDoc->m_dib.GetBitCount(lpSrcDib); //获取图像位深 lSrcLineBytes=pDoc->m_dib.GetReqByteWidth(lSrcWidth * lpSrcBitCount); // 计算图象每行的字节数 ///////////////////////////////////////////////////////////////////////////////////////////////// unsigned char* lpSrc; // 循环变量 LONG i; LONG j; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lSrcWidth * 24); BITMAPINFOHEADER *pHead; RGBQUAD* pColorTable; int lineByteNew; int biBitCount=8; lineByteNew=(lSrcWidth * biBitCount/8+3)/4*4; //申请位图数据所需要的空间,读位图数据进内存 unsigned char *pBmpBufNew; pBmpBufNew=new unsigned char[lineByteNew * lSrcHeight + sizeof(BITMAPINFOHEADER) + 256*4];//申请新图像的空间 memcpy(pBmpBufNew,(unsigned char *)lpSrcDib,sizeof(BITMAPINFOHEADER));//信息头拷贝 pHead=(BITMAPINFOHEADER *)pBmpBufNew; pHead->biBitCount=8;//改变位数, pHead->biHeight=lSrcHeight; pHead->biWidth=lSrcWidth; pHead->biClrUsed=256; pHead->biClrImportant=0; pHead->biCompression=0; pHead->biPlanes=1; pHead->biSize=40; pHead->biSizeImage=lineByteNew*lSrcHeight; pHead->biXPelsPerMeter=0; pHead->biYPelsPerMeter=0; pColorTable=(RGBQUAD*)(pBmpBufNew +sizeof(BITMAPINFOHEADER)); //灰度图像有颜色表,且颜色表表项为 if(biBitCount==8){ //申请颜色表所需要的空间,给颜色表赋值 for(int i=0;i<256;i++) { pColorTable[i].rgbBlue=i; pColorTable[i].rgbGreen=i; pColorTable[i].rgbRed=i; pColorTable[i].rgbReserved=0; } } int Red,Green,Blue,Gray,offset; offset=sizeof(BITMAPINFOHEADER)+256*4; //逐行扫描 for(i = 0; i < lSrcHeight; i++) { //逐列扫描 for(j = 0; j < lSrcWidth; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpSrcStartBits+ lLineBytes * (lSrcHeight - 1 - i) + j*3; Blue = *lpSrc; Green=*(++lpSrc); Red=*(++lpSrc); Gray= (BYTE)(0.299 * Red + 0.587 * Green + 0.114 * Blue + 0.5); // 变换 lpSrc= (unsigned char*)(pBmpBufNew+offset) + lineByteNew * (lSrcHeight - 1 - i) + j; *lpSrc =Gray; } } //拷贝 memcpy(lpSrcDib,pBmpBufNew,lineByteNew * lSrcHeight+ sizeof(BITMAPINFOHEADER) + 256*4); delete []pBmpBufNew; //设置文档修改标志 pDoc->SetModifiedFlag(true); //更新视图 pDoc->UpdateAllViews(NULL); //解除锁定 ::GlobalUnlock((HGLOBAL)pDoc->GetHObject ()); }
3.实验结果
四、24位彩色转8位彩色
1.原理:1.建立八叉树,合并子树。将拥有256*256*256色的真彩色图像,转换为256色图像。八叉树节点的特性就是每个节点最多有8个字节点,编号为0~7 。以RGB值建立八叉树,首先建立根节点,然后分别以RGB的每一位分别组成一个0~7的值,依次插入树中。以RGB(123,54,78)为例。
以此类推,将所有的RGB值逐层插入到八叉树中,在每个节点上,记录所有经过的节点的RGB值的总和,以及RGB颜色个数。插入的过程中,如果节点不存在,则需要创建新的节点,然后增加节点计数以及RGB各分量的总和.当在插入时,发现节点已经存在,且是叶子节点,则停止该颜色后续层数节点的插入。插入完一个颜色之后,如果叶子节点数超过了我们要得到的颜色数(256色需要得到256种颜色),这时候就需要合并一些呀字节点了,使的叶子节点的个数不超过我们要得到的颜色数。
由于越底层的节点,数据的敏感度越低,所以,我们将从最底层的节点开始合并。按节点计数值小的优先合并策略,将其字节点的所有RGB分量以及节点计数全部记录到该节点中,并删除其所有子节点。依此进行,直到合并后的叶子数符合要求为止。
2.提取调色板 按照上述的步骤插入完所有的颜色之后,便建立起一颗叶子节点不超过256的八叉树。此时,取出叶子节点中的RGB分量的平均值(分量总和 / 节点计数),即是得到的调色板颜色值。
3.匹配调色板索引 所谓匹配调色板索引,就是根据原始的RGB值,在调色板中查找出最接近的颜色的索引。对每个RGB颜色,分别对调色板数据求各分量的差值的平方和,求的的最小值对应的调色板颜色的索引,即是该RGB颜色匹配到的调色板索引。
细节:1.定义直接插入排序(sort1)和快速排序(sort2)两种排序方式,通过两种排序方式,建立八叉树。计算各个像素值的使用频率,将使用最高的前256种,定义为调色板。其中usedTimes数组中是各颜色使用频率。并用原来的useTimes数组来保存索引值
2.用PFC函数计算,当像素值不在颜色表256位时,寻找这256种中最接近的颜色。
代码实现
//数学函数 int PFC(int color1, int color2) { int x,y,z; x = (color1 & 0xf) - (color2 & d5e6 0xf); y = ((color1>>4) & 0xf) - ((color2>>4) & 0xf); z = ((color1>>8) & 0xf) - ((color2>>8) & 0xf); return (x*x + y*y + z*z); } //直接插入排序 int Sort1(int *src, int *attach, int n) { int cur, cur1; int i,j,k=0; for (i = 1; i < n; i++) { cur = src[i]; cur1 = attach[i]; for (j = i - 1; j >= 0; j--) { if (cur > src[j]) { src[j+1] = src[j]; attach[j+1] = attach[j]; } else break; } src[j+1] = cur; attach[j+1] = cur1; } return 0; } //快速排序 int Sort2(int *src, int *attach, int n) { if (n <= 12) return Sort1(src, attach, n); int low = 1, high = n - 1; int tmp; while (low <= high) { while (src[low] >= src[0]) { if (++low > n - 1) break; } while (src[high] < src[0]) { if (--high < 1) break; } if (low > high) break; { tmp = src[low]; src[low] = src[high]; src[high] = tmp; tmp = attach[low]; attach[low] = attach[high]; attach[high] = tmp; } low++; high--; } { tmp = src[low - 1]; src[low - 1] = src[0]; src[0] = tmp; tmp = attach[low - 1]; attach[low - 1] = attach[0]; attach[0] = tmp; } if (low > 1) Sort2(src, attach, low - 1); if (low < n) Sort2(&src[low], &attach[low], n - low); return 0; } int Transfer(WORD *color24bit, int len, BYTE *Index, RGBQUAD *mainColor) { int usedTimes[4096] = {0}; int miniColor[4096]; int i; for ( i = 0; i < 4096; i++) miniColor[i] = i; i = 0; for (i = 0; i < len; i++) { assert(color24bit[i] < 4096); usedTimes[color24bit[i]]++; } int numberOfColors = 0; for (i = 0; i < 4096; i++) { if (usedTimes[i] > 0) numberOfColors++; } //对usedTimes进行排序,排序过程中minColor数组(保存了颜色值)也作与useTimes //数组相似的交换 Sort2(usedTimes, miniColor, 4096); //usedTimes数组中是各颜色使用频率,从高到低排列,显然第numberOfColor个之后的都为0 //miniColor数组中是相应的颜色数据 //将前256个颜色数据保存到256色位图的调色盘中 for (i = 0; i < 256; i++) { mainColor[i].rgbBlue = (BYTE)((miniColor[i]>>8)<<4); mainColor[i].rgbGreen = (BYTE)(((miniColor[i]>>4) & 0xf)<<4); mainColor[i].rgbRed = (BYTE)((miniColor[i] & 0xf)<<4); mainColor[i].rgbReserved = 0; } int *colorIndex = usedTimes;//用原来的useTimes数组来保存索引值 memset(colorIndex, 0, sizeof(int) * 4096); if (numberOfColors <= 256) { for (i = 0; i < numberOfColors; i++) colorIndex[miniColor[i]] = i; } else//为第256之后的颜色在前256种颜色中找一个最接近的 { for (i = 0; i < 256; i++) colorIndex[miniColor[i]] = i; int index, tmp, tmp1; for (i = 256; i < numberOfColors; i++) { tmp = PFC(miniColor[0], miniColor[i]); index = 0; for (int j = 1; j < 256; j++) { tmp1 = PFC(miniColor[j], miniColor[i]); if (tmp > tmp1) { tmp = tmp1; index = j; } } colorIndex[miniColor[i]] = index; } } //记录各点颜色数据的索引值,即256色位图的颜色数据 for (i = 0; i < len; i++) { assert(colorIndex[color24bit[i]] < 256); Index[i] = colorIndex[color24bit[i]]; } return 1; } //24位转8位彩色------------------------------------------------------------------------------ void CImgtestView::On248color() { // TODO: 在此添加命令处理程序代码 CImgtestDoc* pDoc=GetDocument();// 获取文档 //////////////////////////////////////////////////////////////////////////////////////////////// long lSrcLineBytes; //图象每行的字节数 long lSrcWidth; //图象的宽度和高度 long lSrcHeight; int lpSrcBitCount; //图像的位深 LPSTR lpSrcDib; //指向源图象的指针 LPSTR lpSrcStartBits; //指向源像素的指针 lpSrcDib= (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHObject());// 锁定DIB if (!lpSrcDib) return; if (pDoc->m_dib.GetBitCount(lpSrcDib) != 24)// 判断是否是24-bpp位图 { AfxMessageBox(L"对不起,不是24位图!");// 警告 ::GlobalUnlock((HGLOBAL) pDoc->GetHObject());// 解除锁定 return; //返回 } lpSrcStartBits=pDoc->m_dib.GetBits(lpSrcDib); // 找到DIB图象像素起始位置 lSrcWidth= pDoc->m_dib.GetWidth(lpSrcDib); // 获取图象的宽度 lSrcHeight= pDoc->m_dib.GetHeight(lpSrcDib); // 获取图象的高度 lpSrcBitCount=pDoc->m_dib.GetBitCount(lpSrcDib); //获取图像位深 lSrcLineBytes=pDoc->m_dib.GetReqByteWidth(lSrcWidth * lpSrcBitCount); // 计算图象每行的字节数 ///////////////////////////////////////////////////////////////////////////////////////////////// unsigned char* lpSrc; // 循环变量 LONG i; LONG j; // 图像每行的字节数 LONG lLineBytes; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(lSrcWidth * 24); BITMAPINFOHEADER *pHead; RGBQUAD* pColorTable=NULL; int lineByteNew; int biBitCount=8; lineByteNew=(lSrcWidth * biBitCount/8+3)/4*4; //灰度图像有颜色表,且颜色表表项为 if(biBitCount==8){ //申请颜色表所需要的空间,给颜色表赋值 pColorTable=new RGBQUAD[256]; memset(pColorTable, 0, sizeof(RGBQUAD)*256); } BYTE* Index = new BYTE[lineByteNew*lSrcHeight]; //图像数据区的数据(保存在Index中) WORD* shortColor = new WORD[lineByteNew*lSrcHeight]; //颜色的高4位 int iRed, iGreen, iBlue; for (int i = 0; i < lSrcHeight; i++) {//取RGB颜色的高4位 for(int j=0;j<lSrcWidth;j++) { lpSrc = (unsigned char*)lpSrcStartBits+ lLineBytes * (lSrcHeight - 1 - i) + j*3; iBlue = (*lpSrc)>>4; iGreen=(*(++lpSrc))>>4; iRed=(*(++lpSrc))>>4; shortColor[lineByteNew * (lSrcHeight - 1 - i) + j] =(iBlue<<8) + (iGreen<<4) + iRed ; } } //调用转换函数 24color To->8color Transfer(shortColor, lineByteNew*lSrcHeight, Index, pColorTable); /* Transfer(shortColor, nData/3, Index, mainColor); */ //申请位图数据所需要的空间,读位图数据进内存 unsigned char *pBmpBufNew; pBmpBufNew=new unsigned char[sizeof(BITMAPINFOHEADER) + 256*4];//申请新图像的空间 memcpy(pBmpBufNew,(unsigned char *)lpSrcDib,sizeof(BITMAPINFOHEADER));//信息头拷贝 pHead=(BITMAPINFOHEADER *)pBmpBufNew; pHead->biBitCount=8;//改变位数, pHead->biHeight=lSrcHeight; pHead->biWidth=lSrcWidth; pHead->biClrUsed=256; pHead->biClrImportant=0; pHead->biCompression=0; pHead->biPlanes=1; pHead->biSize=40; pHead->biSizeImage=lineByteNew*lSrcHeight; pHead->biXPelsPerMeter=0; pHead->biYPelsPerMeter=0; //拷贝 memcpy(lpSrcDib,pBmpBufNew, sizeof(BITMAPINFOHEADER)); memcpy(lpSrcDib+sizeof(BITMAPINFOHEADER),pColorTable, sizeof(RGBQUAD)*256); memcpy(lpSrcDib+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256,Index,lineByteNew*lSrcHeight); delete []Index; delete []shortColor; //设置文档修改标志 pDoc->SetModifiedFlag(true); //更新视图 pDoc->UpdateAllViews(NULL); //解除锁定 ::GlobalUnlock((HGLOBAL)pDoc->GetHObject ()); }
相关文章推荐
- 基于mfc数字图像处理的小软件pdd-转换图片成RGB通道,反色,黑白,灰度图片
- Opencv (Opencv2)结合MFC学习数字图像处理---图片解码(1)
- [数字图像处理]灰度变换——反转,对数变换,伽马变换,灰度拉伸,灰度切割,位图切割
- 数字图像处理之位图在计算机中的存储结构
- 【数字图像处理】五.MFC图像点运算之灰度线性变化、灰度非线性变化、阈值化和均衡化处理详解
- 基于mfc数字图像处理的小软件pdd-量化灰度图像
- Opencv (Opencv2)结合MFC学习数字图像处理【2】---图片解码
- [数字图像处理]灰度变换——反转,对数变换,伽马变换,灰度拉伸,灰度切割,位图切割
- 基于mfc的数字图像处理的小软件pdd的诞生-打开图片及保存图片
- 数字图像处理之位图在计算机中的存储结构
- int类型转换成字符串和字符串转换成int类型以及在MFC静态文本框显示数字的方式方法
- 数字图像处理_真彩图转换灰度图_纯C
- [数字图像处理]灰度变换——反转,对数变换,伽马变换,灰度拉伸,灰度切割,位图切割
- Opencv (Opencv2)结合MFC学习数字图像处理---图片解码(2)
- Opencv (Opencv2)结合MFC学习数字图像处理【3】---显示图片
- 数字图像处理编程入门—第1章 Windows位图和调色板
- Opencv (Opencv2)结合MFC学习数字图像处理---图片解码(3)
- Opencv (Opencv2)结合MFC学习数字图像处理【1】---建立工程
- 数字图像处理 颜色空间RGB、HSI、CMYK、YUV的相互转换
- 数字图像处理MFC程序设计之灰度图像的线性变换