【TIFF】八.价值五千元的TIFF存储代码,你确定不来看看?
程序员文章站
2022-03-11 10:33:58
...
目录
首先准备几张图片
我要把这几张图片拼成一张大图,拼接效果如下所示:
你看看值不值五千块钱?
继续往下看。
一 准备图片
std::vector<std::string> fileNames;
fileNames.push_back("./Scan-Compare/1.jpg");
fileNames.push_back("./Scan-Compare/2.jpg");
fileNames.push_back("./Scan-Compare/3.jpg");
fileNames.push_back("./Scan-Compare/4.jpg");
fileNames.push_back("./Scan-Compare/5.jpg");
fileNames.push_back("./Scan-Compare/6.jpg");
std::vector<cv::Mat> mats;
CTileTiff tiff("D:/1.tiff");
for (int i = 0; i < fileNames.size(); i++)
{
cv::Mat img = cv::imread(fileNames[i]);
cv::Mat dst;
resize(img, dst, Size(4096, 4096), 0.0, 0.0);
//cv::imshow("dst", dst);
cv::cvtColor(dst, dst, CV_BGR2RGB);
mats.push_back(dst);
}
二.设置TIFF的文件信息
bool CTileTiff::SetTileInfo(int nTileW, int nTileH, int nLayer,int nHeight,int nWidth)
{
m_nTileWidth = nTileW;
m_nTileHeight = nTileH;
m_nLayers = nLayer;
m_nWidth = nWidth;
m_nHeight = nHeight;
}
三.存储每一张图片
bool CTileTiff::SaveImage(cv::Mat &img, const int nLeft, const int nTop,
const int nRight, const int nBottom)
{
int nX = nLeft, nY = nTop;
//int nWidth = nRight - nX, nHeight = nBottom - nY;
const int nRows = img.rows / m_nTileHeight;
const int nCols = img.cols / m_nTileWidth;
cout << "nRows,nCols:" << nRows << "," << nCols << endl;
const int nPitch = (nRight - nLeft) * 3;
const int nLayerID = 0;
for (int i = 0; i < nRows; ++i)
{
const int nT = nY + i * m_nTileHeight;
const int nB = nT + m_nTileWidth;
for (int j = 0; j < nCols; ++j)
{
const int nL = nX + j * m_nTileWidth;
const int nR = nL + m_nTileWidth;
cout << nT << "," << nL << endl;
cv::Rect rect(j * m_nTileWidth, i * m_nTileHeight, m_nTileWidth, m_nTileHeight);
cv::Mat roi = img(rect).clone();
bool bOk = saveTile(roi, nL, nT, nR, nB, nLayerID);
if (!bOk)
{
continue;
}
}
}
//这里是为了下采样,按金字塔格式存储
int nSubW = nCols, nSubH = nRows;
int nSubLayer = nLayerID;
while (true)
{
nSubW /= 2;
nSubH /= 2;
nSubLayer++;
if (1 > nSubW || 1 > nSubH)
{
break;
}
const int nScale = 1 << nSubLayer;
for (int i = 0; i < nSubH; ++i)
{
const int nT = nY + i * m_nTileWidth * nScale;
const int nB = nT + m_nTileHeight * nScale;
for (int j = 0; j < nSubW; ++j)
{
const int nL = nX + j * m_nTileWidth * nScale;
const int nR = nL + m_nTileWidth * nScale;
cv::Rect rect(nL - nX, nT - nY, m_nTileWidth * nScale, m_nTileHeight * nScale);
cv::Mat roi = img(rect).clone();
cv::Mat resized;
ResizeImg(roi.data,
resized.data, m_nTileWidth * nScale, m_nTileHeight * nScale, 3, nPitch, m_nTileWidth, m_nTileHeight,
3, m_nTileWidth*3);
bool bOk = saveTile(resized, nL, nT, nR, nB, nSubLayer);
if (!bOk)
{
continue;
}
}
}
}
return true;
}
四. 存储每一个tile
bool CTileTiff::saveTile(cv::Mat& roi, const int nL, const int nT,const int nR, const int nB, const int nLayer)
{
if (roi.empty())
{
return false;
}
const int nWidth = nR - nL;
const int nHeight = nB - nT;
int nLength = 0;
cout << nL << "," << nT << "," << nR << "," << nB << endl;
try
{
TIFFSetDirectory(m_pFile, nLayer);
TIFFSetField(m_pFile, TIFFTAG_IMAGEWIDTH, m_nWidth/(nLayer+1));
TIFFSetField(m_pFile, TIFFTAG_IMAGELENGTH, m_nHeight/(nLayer + 1));
TIFFSetField(m_pFile, TIFFTAG_TILEWIDTH, m_nTileWidth);
TIFFSetField(m_pFile, TIFFTAG_TILELENGTH, m_nTileHeight);
TIFFSetField(m_pFile, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE);
TIFFSetField(m_pFile, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(m_pFile, TIFFTAG_SAMPLESPERPIXEL, 3);
TIFFSetField(m_pFile, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(m_pFile, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
TIFFSetField(m_pFile, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
int nJpegQuality = 60;
TIFFSetField(m_pFile, TIFFTAG_JPEGQUALITY, nJpegQuality);
//根据需要设置分辨率
/*if (nLayer == 0)
{
float fPixelSize = 0.00068f;
int nScale = 20;
fPixelSize = fPixelSize * 100 / max(1, nScale);
TIFFSetField(m_pFile, TIFFTAG_XRESOLUTION, 1.0 / (fPixelSize / 10));
TIFFSetField(m_pFile, TIFFTAG_YRESOLUTION, 1.0 / (fPixelSize / 10));
TIFFSetField(m_pFile, TIFFTAG_RESOLUTIONUNIT, 3);
}*/
// save tile information
const int nTileRow = nT / m_nTileHeight;
const int nTileCol = nL / m_nTileWidth;
int tiffIndex = nTileRow * (m_nWidth / (nLayer+1)/m_nTileWidth) + nTileCol;
cout << "tiffIndex:" << tiffIndex << "," << nTileRow << "," << nTileCol << "," << endl;
TIFFWriteEncodedTile(m_pFile, tiffIndex, (void*)roi.data, m_nTileWidth * m_nTileHeight * 3);
TIFFWriteDirectory(m_pFile);
}
catch (const std::exception& e)
{
//LOG_E("write tiff error:%s", e.what());
}
return true;
}
五.简单的存储DEMO
int nWidth = mats[0].cols;
int nHeight = mats[0].rows;
tiff.SetTileInfo(256, 256, 1, nHeight*2, nWidth*3);
//第一行. 这样是为了demo 看起来容易理解,真正开发的时候你至少得用循环吧。。。
tiff.SaveImage(mats[0], 0, 0, nWidth, nHeight);
tiff.SaveImage(mats[1], nWidth, 0, nWidth * 2, nHeight);
tiff.SaveImage(mats[2], nWidth*2, 0, nWidth * 3, nHeight);
//第二行
tiff.SaveImage(mats[3], 0, nHeight, nWidth, nHeight*2);
tiff.SaveImage(mats[4], nWidth, nHeight, nWidth * 2, nHeight * 2);
tiff.SaveImage(mats[5], nWidth * 2, nHeight, nWidth * 3, nHeight * 3);
六.源码
具体代码见 https://github.com/Mayi-Keiji/libtiff-x64-build.git
如果对代码有疑问的,可以在评论区留言~~~