I.はじめに
フォーマット変換は、実際に、私はマットは、BMPの電源を入れた後、関数imwriteインタフェースは直接.BMP画像データとして保存することができることに気づいたマットを実現しますが、画像が送られているので、変換は、メモリに変換され、次の話をしている、非常に一般的です識別サーバマットは、明らかに最初の.bmpファイルとして保存し、その後識別サービスを送信するためにバイナリ形式でファイルを読み取るが、メモリ内で直接その変換を完了すべきであることはできません。
二、マットやBMPデータ構造
マットデータ構造
マット行列データ構造は、ヘッドとマトリックスのデータを指すポインタから構成されていますマット= +マトリックスマトリクスデータ先頭ポインタ、UCHAR *はデータが共通である次のコードスニペットマットクラス、マットのUMatData * U GPUバージョン、マットUMATは、GPU画像処理を呼ぶ前に変換する必要があります。
int flags; //! the matrix dimensionality, >= 2 int dims; //! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions int rows, cols; //! pointer to the data uchar* data; //! helper fields used in locateROI and adjustROI const uchar* datastart; const uchar* dataend; const uchar* datalimit; //! custom allocator MatAllocator* allocator; //! and the standard allocator static MatAllocator* getStdAllocator(); static MatAllocator* getDefaultAllocator(); static void setDefaultAllocator(MatAllocator* allocator); //! internal use method: updates the continuity flag void updateContinuityFlag(); //! interaction with UMat UMatData* u; MatSize size; MatStep step;
BMPデータ構造
Windowsビットマップ形式の画像の基本的な表示である第一ビットマップとディスプレイに変換する必要があり、絵がWindowsの下に表示されています。一般にビットマップとして知られているビットマップ、任意の圧縮せず、比較的大きな画像は、他の画像フォーマットは、対応する圧縮アルゴリズムに基づいているが、それらに基づいて生成されます。
ビットマップ=ヘッダ情報ヘッダ+ + +パレット画素データ
ヘッダー:BITMAPFILEHEADER、14バイトのサイズ
ヘッダー:BITMAPINFOHEADER、40バイトのサイズ
パレット:RGBQUAD [n]は、サイズの4×nバイトは、アレイとして理解することができ、各要素が一つの色に対応し、インデックスカラー、パレット、及びグレースケールの画素値は、一般に、パレットに分割されていますカラーパレットは、グレースケールのパレット名は、モノクロ画像、カラーパレットを用いてカラー画像を使用することを意味し、パレットは、主画像のサイズを縮小するために、唯一のパレットのみをビットマップ1,4,8必要、色の種類に対応するパレットは、それは16ビットのRGB図であってもよいし、あまりにも多くのスペースを占有する場合は、様々な色からなる組成物に十分なスペースが2,16,256.16,24,32ビットマップです。 (556)またはRGB(565)、24ビットマップRGB(888)、32ビットマップは、RGBA(8888)です。
画素データ:UCHARの* pを。
アイデア変換の第三に、実現
マット明確なデータ構造およびBMP、それは非常に単純な変換、マット予め(すなわち、関連するメンバ変数マットクラスである)BMPファイルのヘッダ情報に割り当てられ、マットBMP、データに対するデータポインタヘッドを回しますBMPのデータ部分をコピーし、BMPマットターンは同じ理由です。
四、マットは、BMPを回します
int CAlgorithm::Mat2Bmp(cv::Mat * pMat, uchar * & pBmp, ulong & size)
{
if (!pMat)
{
return -1;
}
/////////////////////////////////创建bmp空白图片///////////////////////////
int depth = pMat->depth();
int channels = pMat->channels();
int width = pMat->cols;
int height = pMat->rows;
// 获取图像每个像素的位数
// depth 代表每个通道元素的宽度,0:CV_8U
uint pixelSize = (8 << (depth / 2)) * channels;
// bmp规定每一行的长度必须是4的整数倍, pMat->cols * pixelSize / 8 为每一行有效数据长度
// 其实OpenCV已经规定每行长度必须是4的整数倍,多以Mat也是
//uint lineSize = ((width * pixelSize / 8) + 3) / 4 * 4;
uint lineSize = width * pixelSize / 8;
// 计算需要的调色板的大小,以便为bmp图像申请内存空间
// 只有1、4、8位图才需要调色板(1->2, 4->16, 8->256),因为16、24、32位有足够的空间以便自由组合
uint colorTableSize = 0;
// 当前只支持8位图
if (1 == pixelSize)
{
colorTableSize = 2 * sizeof(RGBQUAD);
RGBQUAD* pColorTable = (RGBQUAD*)(&pBmp[sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)]);
for (int i = 0; i < 2; ++i)
{
// 灰阶调色板
pColorTable[i].rgbRed = i;
pColorTable[i].rgbGreen = i;
pColorTable[i].rgbBlue = i;
// 也可以创建彩色调色版
}
}
else if (4 == pixelSize)
{
colorTableSize = 16 * sizeof(RGBQUAD);
RGBQUAD* pColorTable = (RGBQUAD*)(&pBmp[sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)]);
for (int i = 0; i < 16; ++i)
{
// 灰阶调色板
pColorTable[i].rgbRed = i;
pColorTable[i].rgbGreen = i;
pColorTable[i].rgbBlue = i;
// 也可以创建彩色调色版
}
}
if (8 == pixelSize)
{
colorTableSize = 256 * sizeof(RGBQUAD);
RGBQUAD* pColorTable = (RGBQUAD*)(&pBmp[sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)]);
for (int i = 0; i < 256; ++i)
{
// 灰阶调色板
pColorTable[i].rgbRed = i;
pColorTable[i].rgbGreen = i;
pColorTable[i].rgbBlue = i;
// 也可以创建彩色调色版
}
}
// bmp图片的大小, sizeof(BITMAPFILEHEADER) = 14, sizeof(BITMAPINFOHEADER) = 40
size = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTableSize + height * lineSize;
pBmp = (uchar*)malloc(size);
if(!pBmp)
{
return -2;
}
memset(pBmp, 0, size);
/////////////////////////////////为bmp图片的文件头赋值/////////////////////////////////
BITMAPFILEHEADER * pFileHead = (BITMAPFILEHEADER *)pBmp;
pFileHead->bfType = 0x4D42; // 0x4D42 代表 “BM”,位图标志
pFileHead->bfSize = size;
pFileHead->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTableSize; // 图像数据偏移量
/////////////////////////////////为bmp图片的信息头赋值/////////////////////////////////
BITMAPINFOHEADER * pInfoHead = (BITMAPINFOHEADER *)(&pBmp[sizeof(BITMAPFILEHEADER)]);
pInfoHead->biSize = 40; // 信息头的大小
pInfoHead->biWidth = width;
pInfoHead->biHeight = height;
pInfoHead->biPlanes = 1; // 图像平面数,rgb为1?什么时候大于1?
pInfoHead->biBitCount = pixelSize; // 图像每个像素所占的位数
pInfoHead->biCompression = 0; // 0:不压缩,1:REL8, 2:REL4
pInfoHead->biSizeImage = height * lineSize; // 图像数据大小
pInfoHead->biXPelsPerMeter = 0; // 水平方向像素/米,分辨率
pInfoHead->biYPelsPerMeter = 0; // 垂直方向像素/米,分辨率
pInfoHead->biClrUsed = 0; // BMP图像使用的颜色,0:表示使用全部颜色
pInfoHead->biClrImportant = 0; // 重要的颜色数,0:所有的颜色都重要,当显卡不能够显示所有颜色时,辅助驱动程序显示颜色
///////////////////////////////////为bmp图片的调色板赋值/////////////////////////////////
//// 8位图
//if (8 == pixelSize)
//{
// // 只有1、4、8位图才需要调色板(1->2, 4->16, 8->256),因为16、24、32位有足够的空间以便自由组合
// RGBQUAD* pColorTable = (RGBQUAD*)(&pBmp[sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)]);
// for (int i = 0; i < 256; ++i)
// {
// // 灰阶调色板
// pColorTable[i].rgbRed = i;
// pColorTable[i].rgbGreen = i;
// pColorTable[i].rgbBlue = i;
// // 也可以创建彩色调色版
// }
//}
/////////////////////////////////为bmp图片的图像数据赋值/////////////////////////////////
// BMP 和 Mat 数据都是自左向右,但是BMP是自下而上,Mat是自上而下,故而在数据转换时需要颠倒数据上下位置
//uchar * pBmpData = pBmp + pFileHead->bfOffBits;
uchar * pBmpData = pBmp + pFileHead->bfOffBits + height * lineSize; // 最后一行尾地址
uchar * pMatData = pMat->data; // 第一行首地址
// 将Mat从上往下一行一行拷给BMP
for (int i = 0; i < height; ++i)
{
// 这里的 width 代表水平方向的像素个数,但是每个像素占1个字节,通过查表索引(RGB
// 每次拷贝一行
pBmpData -= lineSize;
memcpy(pBmpData, pMatData, lineSize);
pMatData += lineSize;
}
return 0;
}
五、BMPのターンマット
int CAlgorithm::Bmp2Mat(uchar * pBmp, cv::Mat & mat)
{
// 获取文件头信息
if (!pBmp)
{
return -1;
}
BITMAPFILEHEADER * pFileHead = (BITMAPFILEHEADER *)pBmp;
if (pFileHead->bfType != 0x4D42)
{
return -2;
}
BITMAPINFOHEADER* pInfoHead = (BITMAPINFOHEADER *)(pBmp + sizeof(BITMAPFILEHEADER));
long height = pInfoHead->biHeight;
long width = pInfoHead->biWidth;
ulong dataSize = pInfoHead->biSizeImage;
uchar * pMatData = (uchar *)malloc(dataSize);
memset(pMatData, 0, dataSize);
// bmp数据填充数据为至下而上、至左而右,mat为至上而下、至左而右
uint lineSize = width * (pInfoHead->biBitCount) / 8;
// 最后一行尾地址
uchar * pBmpData = (uchar *)(pBmp + pFileHead->bfSize); // 每个像素占一个字节
for (int h = 0; h < height; ++h)
{
pBmpData -= lineSize;
memcpy(pMatData, pBmpData, lineSize); // 复制整行
pMatData += lineSize;
}
// Mat数据指针移到最前面
pMatData -= dataSize;
mat.create(height, width, CV_MAKETYPE(CV_8U, (pInfoHead->biBitCount) / 8));
memcpy(mat.data, pMatData, dataSize);
free(pMatData);
return 0;
}
第六に、少し経験
改善のBMPマットターンのコードベース、BMPマットを達成するのは、独自の電源を入れ、機能の発見を実現することは困難ではない、我々は週末の時間を費やし、中にも、完了興味深いたくさんのことを学びました私は多くのことを学びました。