不同图像文件格式之间的转换

by admin on 2020年1月27日

BMPtoAVI

麻烦一下各位大佬们,为何本人写的C++程序将彩色图转换来灰度图后,新创立的图像显示不出来
要读取的图疑似二十四人彩色图,所以没加调色板音讯,不当的地方烦请提出来,感激你们
#include
#include
#include
#pragma pack

用MFC比较轻便把当下荧屏截取,并彰显在和煦程序的UI上。以对话框为例,在实行绘制的单元(举个例子OnPaint)中调用上面这几个函数就会兵贵神速:

//生成avi
void Cbmp2aviDlg::BMPtoAVI(CString szAVIName, CString strBmpDir)
{
 CFileFind finder;
 strBmpDir += _T(“\*.*”);
 AVIFileInit();
 AVISTREAMINFO strhdr;
澳门新葡亰网址下载 , PAVIFILE pfile;
 PAVISTREAM ps;
 int nFrames =0;
 HRESULT hr;

#define PI 3.14159265
using namespace std;
int main()
{
BITMAPFILEHEADE福特Explorer bfh; //位图头文件
BITMAPINFOHEADE普拉多 bih; //位图音讯文件
unsigned char src_buff; //存款和储蓄原图像素数据
unsigned char
dst_buff; //存款和储蓄转变后图像素数据
BYTE tmp;
BYTE z=0; //调色板保留值
int i;
unsigned long j=0; //循环变量
FILE *fin; //要读取的图像
fin=fopen(“D:53119064724449.bmp”,”rb”);

 

 BOOL bFind = finder.FindFile(strBmpDir);
 while(bFind)
 {
  bFind = finder.FindNextFile();
  if(!finder.IsDots() && !finder.IsDirectory())
  {
   CString str = finder.GetFilePath();
   FILE *fp = fopen(str,”rb”);
   BITMAPFILEHEADER bmpFileHdr;
   BITMAPINFOHEADER bmpInfoHdr;
   fseek( fp,0,SEEK_SET);
   fread(&bmpFileHdr,sizeof(BITMAPFILEHEADER),1, fp);
   fread(&bmpInfoHdr,sizeof(BITMAPINFOHEADER),1, fp);

if(fin==NULL)
cout<<“文件张开退步”<<endl;
fread(&bfh,sizeof(BITMAPFILEHEADERubicon卡塔尔国,1,fin卡塔尔国;//读取位图头文件
if(bfh.bfType==0x4d42卡塔尔(قطر‎ //判定是或不是BMP文件
cout<<“那是一个BMP图片”<<endl;
cout<<“图片的尺寸是”<<bfh.bfSize<<endl;

BOOL CSrnShotDlg::GetMyScreen(
                   CDC *pdc                                      // 目标DC
)
{
                   CDC dc;
                   dc.CreateDC("DISPLAY", NULL, NULL, NULL); // 屏幕DC
 
                   CRect clientRect;
                   GetClientRect(clientRect);                                           // 对话框矩形区域
 
                   pdc->BitBlt(0, 0,                                                             // 起始位置
                                     clientRect.Width(),clientRect.Height(),    // 宽高
                                     &dc,                                                                 // 源CDC对象
                                     0, 0,                                                                    // 源位置
                                     SRCCOPY                                                       // 复制方法
                                     );
                   dc.DeleteDC();
                   return TRUE;

}

   BYTE *tmp_buf = NULL;
   if(nFrames ==0 )
   {
    AVIFileOpen(&pfile,szAviName,OF_WRITE | OF_CREATE,NULL);
    _fmemset(&strhdr, 0, sizeof(strhdr));
    strhdr.fccType = streamtypeVIDEO;// stream type
    strhdr.fccHandler = 0;
    strhdr.dwScale = 1;
    strhdr.dwRate = 15; // 15 fps
    strhdr.dwSuggestedBufferSize = bmpInfoHdr.biSizeImage ;
    SetRect(&strhdr.rcFrame, 0, 0, bmpInfoHdr.biWidth,
bmpInfoHdr.biHeight);

fread(&bih,sizeof(BITMAPINFOHEADEHavalState of Qatar,1,fin卡塔尔国; //读取位图音信文件
cout<<“图像的位数是”<<bih.biBitCount<<endl;
src_buff=new unsigned char[bih.biHeight*bih.biWidth*3];
//给缓存区分配内存
fread(src_buff,sizeof,bih.biHeight*bih.biWidth*3,fin卡塔尔国;
//读取图像素数据
dst_buff=new unsigned char[bih.biHeight*bih.biWidth];
//给缓存区分配内部存款和储蓄器
for (unsigned long i=0;i<bih.biHeight*bih.biWidth*3;i+=3State of Qatar//灰度管理
{
tmp=(0.299*src_buff[i]+0.587*src_buff[i+1]+0.114*src_buff[i+2]);
dst_buff[j++]=tmp;
}
bfh.bfSize=bfh.bfOffBits+256*4+bih.biWidth*bih.biHeight;
//256*4是调色板占的字节数
bfh.bfOffBits=bfh.bfOffBits+256*4;
FILE fout=fopen(“D:huayanda2.bmp”,”wb+”State of Qatar; //创造新文件
fwrite(&bfh,sizeof(BITMAPFILEHEADELX570卡塔尔,1,fout卡塔尔国; //写位图头文件
bih.biBitCount=8; //8位灰度图
bih.biSizeImage=( (bih.biWidth+3)/4 )
4*bih.biHeight;
//像素数据大小
fwrite(&bih,sizeof(BITMAPINFOHEADEHaval卡塔尔,1,fout卡塔尔(قطر‎; //写入像素数据
for( i=0;i<256;i++)
{
fwrite(&i,sizeof,1,fout);
fwrite(&i,sizeof,1,fout);
fwrite(&i,sizeof,1,fout);
fwrite(&z,sizeof,1,fout);
}
fwrite(dst_buff,sizeof,bih.biHeight*bih.biWidth,foutState of Qatar;
//写入调色板新闻
cout<<“god job”<<endl;
delete[] src_buff; //释放内部存款和储蓄器
delete[] dst_buff;
return 0;
}

 

    // And create the stream;
    hr = AVIFileCreateStream(pfile,&ps,&strhdr);
    // hr =
AVIStreamSetFormat(ps,nFrames,&bmpInfoHdr,sizeof(bmpInfoHdr));
   }
   tmp_buf = new BYTE[bmpInfoHdr.biWidth * bmpInfoHdr.biHeight *
3];
   fread(tmp_buf, 1, bmpInfoHdr.biWidth * bmpInfoHdr.biHeight * 3,
fp);
   hr =
AVIStreamSetFormat(ps,nFrames,&bmpInfoHdr,sizeof(bmpInfoHdr));
   hr = AVIStreamWrite(ps, // stream pointer
      nFrames , // time of this frame
      1, // number to write
      (LPBYTE) tmp_buf,
      bmpInfoHdr.biSizeImage , // size of this frame
      AVIIF_KEYFRAME, // flags….
      NULL,
      NULL);

接下去改变一下,把显示器截图先转移为灰度(GrayScale)图,再展现出来。转变灰度图的公式是,对一个OdysseyGB值,迈凯伦540C、G、B分别是其3色分量,总结:

   nFrames ++;
   fclose(fp);
  }
 }

              Gray = R * 0.299 + G *0.587 + B *
0.114

 AVIStreamClose(ps);

接下来将Gray分别替换掉原来的3色分量。到这一个地点,很自然想到用SetPixel/GetPixel来促成。因为要对DC进行操作,当然就不能直接在地点GetMyScreen里边的dc直接操作了,为此对GetMyScreen进行一下改建,並且,为了程序的可读性,扩展多少个ConvertTo格雷函数肩负更动(与地点代码分歧之处用铁锈色区分):

 if(pfile != NULL)
  AVIFileRelease(pfile);
 AVIFileExit();
}

 

void ConvertToGray (CDC * pdc)
{
                   for (int xx = 0; xx < clientRect.right ; xx ++)
                                     for (int yy = 0; yy < clientRect.bottom ; yy ++)
                                     {
                                                        COLORREF crTemp = pdc->GetPixel(xx,yy);
                                                        BYTE pixelR = GetRValue(crTemp);
                                                        BYTE pixelG = GetGValue(crTemp);
                                                        BYTE pixelB = GetBValue(crTemp);
                                                        BYTE gray = (BYTE) (pixelR * 0.299 + pixelG * 0.587 +pixelB * 0.114);
                                                        pdc->SetPixelV(xx,yy,RGB(gray, gray, gray));
                                     }
}
 
BOOL CSrnShotDlg::GetMyScreen(
                   CDC *pdc                                      // 目标DC
)
{
                   CDC dc;
                   dc.CreateDC("DISPLAY", NULL, NULL, NULL); // 屏幕DC
 
                   CRect clientRect;
                   GetClientRect(clientRect);                                           // 对话框矩形区域
 
                   CDC          *pMemDC = NULL;                                    // 兼容DC
 
                   pMemDC = new CDC;
                   if (!pMemDC)
                                     return FALSE;
                   pMemDC->CreateCompatibleDC(&dc);
                   ShowWindow(SW_HIDE);
                   pMemDC->BitBlt(0, 0,
                                     clientRect.Width(), clientRect.Height(),
                                     &dc, 0, 0, SRCCOPY);
 
                   ConvertToGray(pMemDC);
 
                   pdc->BitBlt(0, 0,                                                             // 起始位置
                                     clientRect.Width(),clientRect.Height(),    // 宽高
                                     pMemDC,                                                        // 源CDC对象
                                     0, 0,                                                                    // 源位置
                                     SRCCOPY                                                       // 复制方法
                                     );
                   pMemDC->DeleteDC();
                   delete pMemDC;
                   dc.DeleteDC();
                   return TRUE;
}

 

功用出来了,不过并不完备。实际上本身用SetPixelV替代了SetPixel,但出示的进度依旧相当的慢,CPU使用率也非常高。如何进步效用呢?直接改DC上沾满的位图数据就像是是个好法子。上面就转而对CBitmap类对象进行操作。

因为是直接截屏,所以要求先用CDC::GetDeviceCaps带BITSPIXEL参数得到显示屏色深,因为差别色深的位图的积攒方法差别。简要说明一下:十贰位色位图,各样象素占2字节;25位色,每种象素占3字节;三十八位色,各样象素占4字节积累空间。大家可以用CBitmap::GetBitmapBits函数来得到位图数据,这其实是贰个BYTE数组。那一个数组的协会,最简便易行的是贰十六个人色的场所。前边说过了各类象素占3个字节,按数组下标从低到高分别是B、G、Evoque那3色轻重,而三二十一个人色的景观跟25位色雷同,4个字节只但是多了一个阿尔法值。上边正是拍卖25人色深的ConvertToGray24。

 

#define BITS24        (int)(1024 * 768 * 3)
void ConvertToGray24(CBitmap *pBmp)
{
                   LPBYTE lpbits = NULL;
                   lpbits = new BYTE[BITS24];
                   if (!lpbits)
                                     return;
 
                   ZeroMemory(lpbits, BITS24);
                   pBmp->GetBitmapBits(BITS24, lpbits);
                   for (int index = 0, j = 0, k = 0; index < BITS24; index ++)
                   {
                                     lpbits[index] = (BYTE)(0.114 * lpbits[index]);
                                     j = index + 1; k = index + 2;
                                     lpbits[j] = (BYTE)(0.587 * lpbits[j]);
                                     lpbits[k] = (BYTE)(0.299 * lpbits[k]);
                                     lpbits[index] += lpbits[j] + lpbits[k];
                                     lpbits[j] = lpbits[index];
                                     lpbits[k] = lpbits[index];
                                     index = k;
                   }
 
                   pBmp->SetBitmapBits(BITS24, lpbits);
                   delete [] lpbits;
}

 

当GetDeviceCaps(BITSPIXEL卡塔尔重返16的时候,又有三种情景:18个人色和15个人色。15人色的动静下,位图数组使用2字节保存数据,在这之中从高位往低位分别是B、G、奥迪Q5那3色轻重按位5:6:5据有。要求用位操作来收获种种分量的色值:

 

#define GetRValueX(rgb)      ((BYTE)(rgb) & 0x1f)
#define GetGValueX(rgb)      ((BYTE)(((rgb) & 0x07E0) >> 5))
#define GetBValueX(rgb)      ((BYTE)(((rgb) & 0xF800) >> 11))
#define RGBX(r,g,b)
          ((WORD)(((BYTE)(r)|((WORD)((BYTE)(g))<<5))|(((WORD)(BYTE)(b))<<11)))

 

要注意的是因为暗黑分量占用了6bit,其积存精度是别的多个轻重的2倍,所以在张开后继的忖度的时候公式的因数会具备改变。(别的,使用十五人色的适配器少之甚少,其积存准绳也是并吞2字节,但是最高位无意义,其余14人按5:5:5分红,这里不详细研商了。)

#define BITS16        (int)(1024 * 768 * 2)
void ConvertToGray16(CBitmap *pBmp)
{
                   LPBYTE lpbits = NULL;
                   WORD *wBits;
                   lpbits = new BYTE[BITS16];
                   if (!lpbits)
                                     return;
 
                   ZeroMemory(lpDibits, BITS16);
                   pBmp->GetBitmapBits(BITS16, lpbits);
                   for (int index = 0, j = 0, k = 0; index < BITS16; index ++)
                   {
                                     wBits = (WORD *)(lpbits + index);
                                     BYTE pixelR = GetRValueX(*wBits) * 2;
                                     BYTE pixelG = GetGValueX(*wBits) ;     // 注意系数
                                     BYTE pixelB = GetBValueX(*wBits) * 2;
                                     BYTE gray =(BYTE) (pixelR * 0.299 + pixelG * 0.587 +pixelB * 0.114);
                                     *wBits = RGBX(gray / (BYTE)2, gray, gray / (BYTE)2);
                                     index ++;
                   }
                   pBmp->SetBitmapBits(BITS16, lpbits);
                   delete [] lpbits;
}
 

 

终极,第三回改变GetMyScreen:

 

BOOL CSrnShotDlg::GetMyScreen(
                   CDC *pdc                                      // 目标DC
)
{
                   CDC dc;
                   dc.CreateDC("DISPLAY", NULL, NULL, NULL); // 屏幕DC
 
                   CRect clientRect;
                   GetClientRect(clientRect);                                           // 对话框矩形区域
 
                   CDC          *pMemDC = NULL;                                    // 兼容DC
                   CBitmap *pBmp = NULL;                                           // 兼容位图
 
                   pMemDC = new CDC;
                   if (!pMemDC)
                                     return FALSE;
                   pMemDC->CreateCompatibleDC(&dc);
                  
                   pBmp = new CBitmap;
                   if (!pBmp)
                   {
                                     pMemDC->DeleteDC();
                                     delete pMemDC;
                                     return FALSE;
                   }
                   pBmp->CreateCompatibleBitmap(&dc, clientRect.Width(),clientRect.Height());
                   pMemDC->SelectObject(pBmp);
                   ShowWindow(SW_HIDE);
                   pMemDC->BitBlt(0, 0,
                                     clientRect.Width(), clientRect.Height(),
                                     &dc, 0, 0, SRCCOPY);
 
                   switch(pMemDC->GetDeviceCaps(BITSPIXEL))
                   {
                   case: 16
                                     ConvertToGray16(pBmp);
                                     break;
                   case: 24
                                     ConvertToGray24(pBmp);
                                     break;
                   case: 32
                                     ConvertToGray32(pBmp);                          //未给出
                                     break;
                   default:
                                     pBmp->DeleteObject();
                                     pMemDC->DeleteDC();
                                     delete pBmp;
                                     delete pMemDC;
                                     dc.DeleteDC();
                                     return FALSE;
                   }
                   pdc->BitBlt(0, 0,                                                             // 起始位置
                                     clientRect.Width(),clientRect.Height(),    // 宽高
                                     pMemDC,                                                       // 源CDC对象
                                     0, 0,                                                                    // 源位置
                                     SRCCOPY                                                       // 复制方法
                                     );
 
                   pBmp->DeleteObject();
                   pMemDC->DeleteDC();
                   delete pBmp;
                   delete pMemDC;
                   dc.DeleteDC();
                   return TRUE;
}

附文件读取

ConvertBmp24ToBmp256
{
 FILE *fp = fopen(“test.bmp”,”rb”);
 if(!fp)return;

 BITMAPFILEHEADER hdr;
 
 fread(&hdr,1,sizeof(hdr),fp);

 if(!(((hdr.bfType & 0xff) == ‘B’) &&  ((hdr.bfType >> 8) ==
‘M’)))
 {
  fclose(fp);
  return;
 }

 BITMAPINFOHEADER bih;

 fread(&bih,1,sizeof(bih),fp);

 if(bih.biBitCount != 24 || bih.biCompression != 0)
 {
  fclose(fp);
  return;
 }

 unsigned char *pBuf = new unsigned char[bih.biSizeImage];

 fread(pBuf,bih.biSizeImage,sizeof(unsigned char),fp);

 FILE *out = fopen(“testout.bmp”,”wb”);
 if(!out)
 {
  delete []pBuf;
  fclose(fp);
  return;
 }

 unsigned char *pOutBuf = new unsigned char[bih.biWidth *
bih.biHeight];
 unsigned char *tmp = pBuf;
 unsigned char *tmp2 = pOutBuf;
 for(unsigned int i = 0; i < bih.biWidth * bih.biHeight;i++)
 {
  tmp2[i] = (unsigned char)((*tmp) * .114 + *(tmp + 1) * .587 +
*(tmp + 2) * .299);
  tmp += 3;
 }

 RGBQUAD q[256];
 for( i = 0; i < 256; i++)
 {
  q[i].rgbRed = q[i].rgbGreen = q[i].rgbBlue = i;
  q[i].rgbReserved = 0;
 }

 bih.biBitCount = 8;
 bih.biSizeImage = bih.biWidth * bih.biHeight;

 hdr.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
  + sizeof(q) + bih.biSizeImage;
 hdr.bfOffBits += sizeof(q);

 fwrite(&hdr,1,sizeof(hdr),out);
 fwrite(&bih,1,sizeof(bih),out);
 fwrite(q,256,sizeof(RGBQUAD),out);
 fwrite(pOutBuf,bih.biSizeImage,sizeof(unsigned char),out);

 delete []pOutBuf;
 fclose(out);
 delete []pBuf;
 fclose(fp);

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图