请问有tiff/bigtiff写入的demo/example吗
Closed this issue · 24 comments
埃博拉酱您好,请问该库有tiff/bigtiff写入的demo/example吗
例如把一个c++的三维数组写成多层的tiff/bigtiff格式
想感受下该库的写入到底有多快,但是对c++不熟悉,不知道从何下手
tag v1.1.4
是最后一个有<Mex工具>文件夹的版本
找到Mex工具.h头文件之后,因为方法名都是中文,还需要在visual studio中把项目文件编码设置成GB2312
先开启高级保存选项,再打开文件逐一设置保存
保存完成之后,编译成功
这个库公开的API主要是面向MATLAB的。如果你想直接面向C++使用,建议编译为静态库,然后在调用方项目中包含IOmeTiff读写器.h,以及该头文件所依赖的其它头文件。这是一个兼容各种TIFF格式的接口类。
Demo目前是没有,不过我会把它列入后续更新计划。对于你问的将三维数组写出TIFF的情景,可以编写类似于这样的代码:
#include <IOmeTiff读写器.h>
int main()
{
const 颜色 通道颜色[] = {颜色{.整数值 = -1}}; //-1表示白色
IOmeTiff读写器* const 读写器 = IOmeTiff读写器::覆盖创建(L"文件路径.tif",像素类型::UINT16,图像宽度,图像高度,1,图像层数,1,通道颜色,维度顺序::XYCZT); //像素类型应该跟你的数组数据类型一致
读写器->写出像素(像素数组); //像素数组应该是uint16_t[]类型,而不是uint16_t[][][]类型。如果你的原始数据是后者,应该将其展开为一维数组,按照维度从低到高XYZ的顺序。
delete 读写器;
return 0;
}
这个代码Demo是我现写的,没有经过测试,只是反映一个思路,你需要根据你的具体应用进行修改。
关于语言编码,建议更改计算机设置,使用UTF-8编码。首先搜索并打开”区域“
选择【管理】选项卡,然后【更改系统区域设置】
勾选【Beta版:使用 Unicode UTF-8 提供全球语言支持】,【确定】以后重启电脑。
GB2312是一种过时的字符编码,不建议在新的软件开发项目中使用。
感谢您的回复!
我将工程修改成编译静态库
但是产出物看起来更少,没有生成IOmeTiff读写器.lib文件
请问是项目哪里设置不对吗,或者是要在文件里修改公开的API
尝试新建了一个项目,想把IOmeTiff读写器.cpp放在项目里一起编译了,用main.cpp文件替换了dllmain.cpp文件,其他的文件和配置保持一致,编译过了,报链接错误
main文件的内容
#include "pch.h"
#include <IOmeTiff读写器.h>
int main()
{
uint16_t 图像宽度 = 10;
uint16_t 图像高度 = 10;
uint16_t 图像层数 = 3;
const char 像素数组[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const 颜色 通道颜色[] = { 颜色{.整数值 = -1} }; //-1表示白色
IOmeTiff读写器* const 读写器 = IOmeTiff读写器::覆盖创建(L"E:/data/teapot_big_fast.tif", 像素类型::UINT16, 图像宽度, 图像高度, 1, 图像层数, 1, 通道颜色, 维度顺序::XYCZT); //像素类型应该跟你的数组数据类型一致
读写器->写出像素(像素数组); //像素数组应该是uint16_t[]类型,而不是uint16_t[][][]类型。如果你的原始数据是后者,应该将其展开为一维数组,按照维度从低到高XYZ的顺序。
delete 读写器;
return 0;
}
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 LNK2001 无法解析的外部符号 __imp_get_function_ptr TiffWrite E:\projects\Image5D\TiffWrite\Image5D异常.obj 1
错误 LNK2001 无法解析的外部符号 "void __cdecl 异常输出补全(class matlab::mex::MexIORange<class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class matlab::data::Array> > > > &)" (?异常输出补全@@YAXAEAV?$MexIORange@V?$_Vector_iterator@V?$_Vector_val@U?$_Simple_types@VArray@data@matlab@@@std@@@std@@@std@@@mex@matlab@@@Z) TiffWrite E:\projects\Image5D\TiffWrite\MexFunction.obj 1
错误 LNK2001 无法解析的外部符号 mexFunctionAdapter TiffWrite E:\projects\Image5D\TiffWrite\MexFunction.obj 1
错误 LNK2001 无法解析的外部符号 mexDestroyMexFunction TiffWrite E:\projects\Image5D\TiffWrite\MexFunction.obj 1
错误 LNK2001 无法解析的外部符号 mexCreateMexFunction TiffWrite E:\projects\Image5D\TiffWrite\MexFunction.obj 1
首先把静态库扩展名改成lib
然后,带有Mex字段的cpp文件应当从项目中排除,因为这些是面向MATLAB的
最后你似乎没有安装pugixml这个库,可以在NuGet里找一下
设置配置类型为静态库(lib)后, 设置扩展名为.lib
移除带有Mex字段的cpp及头文件,移除导入了<Mex工具.h>的代码,移除Oir和Image5DAPI相关的cpp及头文件
Image5DMex项目生成,得到Image5DMex.lib
安装pugixml
nuget install pugixml
需要使用pugixml.1.13.0\build\native\lib\x64\v143\dynamic\Release目录下的lib文件pugixml.lib
新建项目TiffWriter,
配置属性-->常规-->c++语言标准,选c++ latest
配置属性-->c/c++-->常规-->附加包含目录,配置头文件
F:\projects\pugixml-1.13\src
E:\projects\Image5D\Image5DMex
配置属性-->链接器-->输入-->附加依赖项,配置依赖库
Rpcrt4.lib
Bcrypt.lib
E:\projects\Image5D\+Image5D\+internal\private\Image5DMex.lib
E:\projects\pugixml.1.13.0\build\native\lib\x64\v143\dynamic\Release\pugixml.lib
现在想测试下真实的图片数据写入,再请问下该项目中的通道颜色是什么概念呢,是否类似RGB和RGBA的颜色通道,-1表示白色是指该通道所有像素点都是255的值吗
例如我现在有一个图片数据的buffer,结构是这样的,本身只有一层(一个维度),不是金字塔结构的
我想生成一个多层的tiff, 是直接转换成一维数组,传入写出像素就可以,还是需要另外处理呢
在matlab里转成图片矩阵,是需要这样处理的,将rgb,rgb,rgb转换成rrr,ggg,bbb,否则生成的图像是错乱的
%imgdata是1*N(w*h*3)的矩阵
chan_r = imgdata(1:3:end);
chan_g = imgdata(2:3:end);
chan_b = imgdata(3:3:end);
imgdata_combine = [chan_r, chan_g, chan_b];
mid_imgdata = reshape(imgdata_combine, [width, height, 3]);
T=affine2d([0 1 0;1 0 0;0 0 1]);
new_imgdata=imwarp(mid_imgdata,T);
另外附上matlab写多层tiff/svs的方法,写入也比较快,比libtiff库快很多,但是内存占用很高,还需要安装matlab runtime,因此我更偏向于纯c++的TiffWriter
function writesvs(imgdata, width, height, file_name)
T=affine2d([0 1 0;1 0 0;0 0 1]);%构造空间变换结构T.这里为转置变换矩阵
new_imgdata=imwarp(reshape([imgdata(1:3:end), imgdata(2:3:end), imgdata(3:3:end)], [width, height, 3]),T);
size1 = fix(size(new_imgdata));
size2 = fix(size(new_imgdata)/2);
size3 = fix(size(new_imgdata)/4);
size4 = fix(size(new_imgdata)/8);
t = Tiff(file_name,'w');
%写40X的图像
tagstruct.ImageDescription = "Aperio Image Library |AppMag = 40|MPP = 0.265018";
tagstruct.ImageLength = size1(1);
tagstruct.ImageWidth = size1(2);
tagstruct.Photometric = Tiff.Photometric.RGB;
tagstruct.BitsPerSample = 8;
tagstruct.SamplesPerPixel = 3;
tagstruct.RowsPerStrip = 16;
tagstruct.PlanarConfiguration = Tiff.PlanarConfiguration.Chunky;
tagstruct.Software = 'MATLAB';
tagstruct.TileWidth = 240;
tagstruct.TileLength = 240;
tagstruct.Compression = 7;
tagstruct.JPEGQuality = 85;
setTag(t,tagstruct)
write(t,imresize(new_imgdata, [size1(1) size1(2)]));
writeDirectory(t);
%写20X的图像
tagstruct2.ImageDescription = "Aperio Image Library |AppMag = 20|MPP = 0.51";
tagstruct2.ImageLength = size2(1);
tagstruct2.ImageWidth = size2(2);
tagstruct2.Photometric = Tiff.Photometric.RGB;
tagstruct2.BitsPerSample = 8;
tagstruct2.SamplesPerPixel = 3;
tagstruct2.RowsPerStrip = 16;
tagstruct2.PlanarConfiguration = Tiff.PlanarConfiguration.Chunky;
tagstruct2.Software = 'MATLAB';
tagstruct2.TileWidth = 240;
tagstruct2.TileLength = 240;
tagstruct2.Compression = 7;
tagstruct2.JPEGQuality = 85;
setTag(t,tagstruct2)
write(t,imresize(new_imgdata, [size2(1) size2(2)]));
writeDirectory(t);
%写10X的图像
tagstruct3.ImageDescription = "Aperio Image Library";
tagstruct3.ImageLength = size3(1);
tagstruct3.ImageWidth = size3(2);
tagstruct3.Photometric = Tiff.Photometric.RGB;
tagstruct3.BitsPerSample = 8;
tagstruct3.SamplesPerPixel = 3;
tagstruct3.RowsPerStrip = 16;
tagstruct3.PlanarConfiguration = Tiff.PlanarConfiguration.Chunky;
tagstruct3.Software = 'MATLAB';
tagstruct3.TileWidth = 240;
tagstruct3.TileLength = 240;
tagstruct3.Compression = 7;
tagstruct3.JPEGQuality = 85;
setTag(t,tagstruct3)
write(t,imresize(new_imgdata, [size3(1) size3(2)]));
writeDirectory(t);
%写5X的图像
tagstruct4.ImageDescription = "Aperio Image Library";
tagstruct4.ImageLength = size4(1);
tagstruct4.ImageWidth = size4(2);
tagstruct4.Photometric = Tiff.Photometric.RGB;
tagstruct4.BitsPerSample = 8;
tagstruct4.SamplesPerPixel = 3;
tagstruct4.RowsPerStrip = 16;
tagstruct4.PlanarConfiguration = Tiff.PlanarConfiguration.Chunky;
tagstruct4.Software = 'MATLAB';
tagstruct4.TileWidth = 240;
tagstruct4.TileLength = 240;
tagstruct4.Compression = 7;
tagstruct4.JPEGQuality = 85;
setTag(t,tagstruct4)
write(t,imresize(new_imgdata, [size4(1) size4(2)]));
close(t);
end
关于通道颜色,并不是标准TIFF规定的概念,而是来自OME-TIFF扩展。建议你看一下README中的OME-TIFF部分。它支持任意多个颜色通道,每个通道都可以是任何颜色。它可以退化为RGB通道,但并不是通过Photometric.RGB来实现的。
根据你的描述,你的图像似乎是一个4维数组,分别是宽度X、高度Y、颜色通道C(RGB,3个)和层级Z,数组中每个值都是uint8_t类型。那么你可以将你的数组处理成从低到高XYCZ展开的一维数组。但是需要注意,在覆盖创建的时候,要将像素类型设为UINT8,维度顺序设为XYCZT,SizeT设为1,通道颜色分别设为红绿蓝。
输出的图像文件可以用ImageJ查看,ImageJ允许你将各通道分开或合并查看。
这里需要强调一下,如果你需要确保输出的图像能够被某个特定的图像查看软件识别,你需要先确认那个软件是否支持OME-TIFF扩展。因为本库输出的TIFF是使用OME扩展功能实现的颜色通道(包括RGB),而没有用到TIFF标准自带的Photometric.RGB标签。如果你的图像查看软件依赖于Photometric.RGB标签,本库暂时不能够支持。
我原来理解的是传入图片数据,<IOmeTiff读写器::覆盖创建>里会按照指定的层数,resize传入的图片数据,像上面writesvs函数一样,取原来的1/2, 1/4, 1/8,resize几次写多层
imresize(new_imgdata, [size2(1) size2(2)])
其实是要先把多层的数据都准备好,按XYCZ指定顺序放到<uint8_t* 像素数组>里面。
我在c++里获取到的是一个buffer头,以及buffer的长度
// Return a pointer to the beginning of the buffer.
void * dataPtr = resampleF->GetOutput()->GetPixelContainer()->GetBufferPointer();
itk::Image<PixelType, Dimension>::SizeType size = resampleF->GetOutput()->GetLargestPossibleRegion().GetSize();
long long unsigned int buffer_len = 3 * size[0] * size[1];
那我要复制buffer到数组
// https://stackoverflow.com/questions/46136409/initialising-stdarray-from-pointer-into-a-buffer-elegantly
using arrayType = std::array<uint8_t, buffer_len >;
arrayType imageArray;
std::copy_n(dataPtr , imageArray.size(), imageArray.begin());
如果我要写多层的tiff,先对原来的图像做resample,
// Pseudocode
resampleTwo = resampleF.resize(0.5);
resampleThree = resampleF.resize(0.25);
resampleFour = resampleF.resize(0.125);
再分别从resampleTwo、resampleThree、resampleFour的dataPtr 拷贝出数组,把得到的四个数组拼接成const char 像素数组[]
感觉这样内存占用应该会很高,拷贝效率是不是也很低
之前尝试在c++调用matlab的dll,可以这样setData
mwSize mdim = buffer_len;
mwArray mdisp_image(1, mdim, mxUINT8_CLASS, mxREAL);
mdisp_image.SetData((mxUint8*)dataPtr, mdim);
如果不需要拷贝,是不是可以节省很多内存呢
我不知道c++中有没有其他的方法可以实现类似的操作,较低占用内存高效率地把buffer中的图片数据传递给<IOmeTiff读写器>
为什么要resample呢,你的原始图像和要写出的图像尺寸不同吗?原始数据到底是什么格式,我没有明白。
也就是说,你需要输出多张图,并且它们具有不同的尺寸?尺寸不同的图是不能拼成一个方形数组的。
如果你需要在TIFF内存储每层尺寸不同的多张图像,那你可能只能用标准libtiff,本库的快速读写是假定你的图像是一个规整的方形数组,如果不是的话就无法支持。
是的 不能拼成一个方形数组 但是他们都在一个tiff文件里
这是一个四层金字塔结构tiff的信息,用上面matlab的writesvs函数生成的
D:>tifftools dump matlab_writesvs_big.tiff
-- matlab_writesvs_big.tiff --
Header: 0x4949 <little-endian> <ClassicTIFF>
Directory 0: offset 972625398 (0x39f915f6)
ImageWidth 256 (0x100) SHORT: 50273
ImageLength 257 (0x101) SHORT: 48039
BitsPerSample 258 (0x102) SHORT: <3> 8 8 8
Compression 259 (0x103) SHORT: 7 (JPEG 7 (0x7))
Photometric 262 (0x106) SHORT: 2 (RGB 2 (0x2))
ImageDescription 270 (0x10E) ASCII: Aperio Image Library |AppMag = 40|MPP = 0.265018
SamplesPerPixel 277 (0x115) SHORT: 3
RowsPerStrip 278 (0x116) SHORT: 16
PlanarConfig 284 (0x11C) SHORT: 1 (Chunky 1 (0x1))
Software 305 (0x131) ASCII: SVT-1000
TileWidth 322 (0x142) SHORT: 240
TileLength 323 (0x143) SHORT: 240
TileOffsets 324 (0x144) LONG: <42210> 8 2075 4142 6209 8276 10343 12410 14477 16544 18611 20678 22745 24812 26879 37780 60378 82266 104243 125002 145916 ...
TileByteCounts 325 (0x145) LONG: <42210> 2067 2067 2067 2067 2067 2067 2067 2067 2067 2067 2067 2067 2067 10901 22598 21888 21977 20759 20914 20321 ...
JPEGTables 347 (0x15B) UNDEFINED: <289> b'\xff\xd8\xff\xdb\x00C\x00\x05\x03\x04\x04\x04\x03\x05\x04\x04\x04\x05\x05\x05' ... (estimated quality: 85)
Directory 1: offset 1298856340 (0x4d6af994)
ImageWidth 256 (0x100) SHORT: 25136
ImageLength 257 (0x101) SHORT: 24019
BitsPerSample 258 (0x102) SHORT: <3> 8 8 8
Compression 259 (0x103) SHORT: 7 (JPEG 7 (0x7))
Photometric 262 (0x106) SHORT: 2 (RGB 2 (0x2))
ImageDescription 270 (0x10E) ASCII: Aperio Image Library |AppMag = 20|MPP = 0.51
SamplesPerPixel 277 (0x115) SHORT: 3
RowsPerStrip 278 (0x116) SHORT: 16
PlanarConfig 284 (0x11C) SHORT: 1 (Chunky 1 (0x1))
Software 305 (0x131) ASCII: SVT-1000
TileWidth 322 (0x142) SHORT: 240
TileLength 323 (0x143) SHORT: 240
TileOffsets 324 (0x144) LONG: <10605> 972963619 972965686 972967753 972969820 972971887 972973954 972976021 972983989 973011729 973038538 973063338 973087831 973112952 973136750 973160226 973184764 973208194 973231950 973258353 973280985 ...
TileByteCounts 325 (0x145) LONG: <10605> 2067 2067 2067 2067 2067 2067 7968 27740 26809 24800 24493 25121 23798 23476 24538 23430 23756 26403 22632 27294 ...
JPEGTables 347 (0x15B) UNDEFINED: <289> b'\xff\xd8\xff\xdb\x00C\x00\x05\x03\x04\x04\x04\x03\x05\x04\x04\x04\x05\x05\x05' ... (estimated quality: 85)
Directory 2: offset 1403376936 (0x53a5d528)
ImageWidth 256 (0x100) SHORT: 12568
ImageLength 257 (0x101) SHORT: 12009
BitsPerSample 258 (0x102) SHORT: <3> 8 8 8
Compression 259 (0x103) SHORT: 7 (JPEG 7 (0x7))
Photometric 262 (0x106) SHORT: 2 (RGB 2 (0x2))
ImageDescription 270 (0x10E) ASCII: Aperio Image Library
SamplesPerPixel 277 (0x115) SHORT: 3
RowsPerStrip 278 (0x116) SHORT: 16
PlanarConfig 284 (0x11C) SHORT: 1 (Chunky 1 (0x1))
Software 305 (0x131) ASCII: SVT-1000
TileWidth 322 (0x142) SHORT: 240
TileLength 323 (0x143) SHORT: 240
TileOffsets 324 (0x144) LONG: <2703> 1298941717 1298952188 1298966029 1298980721 1299003834 1299029844 1299055124 1299081650 1299107269 1299133595 1299159845 1299184166 1299210632 1299235347 1299259046 1299283876 1299309761 1299333929 1299358486 1299383097 ...
TileByteCounts 325 (0x145) LONG: <2703> 10471 13841 14692 23113 26010 25280 26526 25619 26326 26250 24321 26466 24715 23699 24830 25885 24168 24557 24611 22555 ...
JPEGTables 347 (0x15B) UNDEFINED: <289> b'\xff\xd8\xff\xdb\x00C\x00\x05\x03\x04\x04\x04\x03\x05\x04\x04\x04\x05\x05\x05' ... (estimated quality: 85)
Directory 3: offset 1429886248 (0x553a5528)
ImageWidth 256 (0x100) SHORT: 6284
ImageLength 257 (0x101) SHORT: 6004
BitsPerSample 258 (0x102) SHORT: <3> 8 8 8
Compression 259 (0x103) SHORT: 7 (JPEG 7 (0x7))
Photometric 262 (0x106) SHORT: 2 (RGB 2 (0x2))
ImageDescription 270 (0x10E) ASCII: Aperio Image Library
SamplesPerPixel 277 (0x115) SHORT: 3
RowsPerStrip 278 (0x116) SHORT: 16
PlanarConfig 284 (0x11C) SHORT: 1 (Chunky 1 (0x1))
Software 305 (0x131) ASCII: SVT-1000
TileWidth 322 (0x142) SHORT: 240
TileLength 323 (0x143) SHORT: 240
TileOffsets 324 (0x144) LONG: <702> 1403399073 1403412315 1403429586 1403449065 1403468923 1403489291 1403508156 1403525771 1403545214 1403566195 1403585685 1403607586 1403627132 1403648336 1403669276 1403689086 1403707550 1403726893 1403746298 1403764216 ...
TileByteCounts 325 (0x145) LONG: <702> 13242 17271 19479 19858 20368 18865 17615 19443 20981 19490 21901 19546 21204 20940 19810 18464 19343 19405 17918 19067 ...
JPEGTables 347 (0x15B) UNDEFINED: <289> b'\xff\xd8\xff\xdb\x00C\x00\x05\x03\x04\x04\x04\x03\x05\x04\x04\x04\x05\x05\x05' ... (estimated quality: 85)
又看了一遍readme,OME规范要求将5个维度的尺寸全部记录在首IFD标签中,这隐含地要求了所有IFD图像帧必须具有相同的高度、宽度和位深度。
我想做的也不是要每一层都不一样的大小,只要有软件能解析打开,进行缩放和平移就可以。
如果满足每一层的图像高度和宽度都是一样的前提,如何创建一个数组是引用buffer里的数据,而不是拷贝一份数据,传递到<IOmeTiff读写器>呢
我看matlab封装的setData底层是这样一个函数
LIBMWMCLMCR_API_EXTERN_C int array_ref_set_numeric_mxUint8(array_ref *obj, const mxUint8* x, mwSize len);
应该是没有拷贝的动作
那你需要计算出图像的各维尺寸,用这个尺寸创建图像文件,然后用写出像素
,将buffer指针传入就行了。传入指针就是不发生拷贝的。但是那之后写出到磁盘的过程无论如何肯定是要拷贝的,这个不可能避免。
集成到真实图像输出的项目,编译通过可以写入了,写出的tif文件格式解析不了,缺OME-XML tags信息,用image_scope这些软件打开,直接就崩溃退出了
这是写入的代码,输入的图像只有一层,就只写了一层
uint16_t 图像宽度 = imageSize[0];
uint16_t 图像高度 = imageSize[1];
uint16_t 图像层数 = 1;
const 颜色 通道颜色[] = { 常用颜色::红色, 常用颜色::绿色, 常用颜色::蓝色 };
wstring wideusername;
for (int i = 0; i < outFilename.length(); ++i)
wideusername += wchar_t(outFilename[i]);
cout << "开始覆盖创建:" << outFilename.c_str() << endl;
IOmeTiff读写器 * const 读写器 =
IOmeTiff读写器::覆盖创建(wideusername.c_str(),
像素类型::UINT8,
图像宽度,
图像高度,
1,
图像层数,
1,
通道颜色,
维度顺序::XYCZT);
读写器->写出像素((uint8_t*)dataPtr);
cout << "写出像素finished" << endl;
delete 读写器;
这是写出图像的文件信息:
D:>tifftools dump image5D.tif
-- image5D.tif --
Header: 0x4949 <little-endian> <BigTIFF>
Directory 0: offset 63 (0x3f)
ImageWidth 256 (0x100) SHORT: 20202
ImageLength 257 (0x101) SHORT: 12133
BitsPerSample 258 (0x102) SHORT: 8
Compression 259 (0x103) SHORT: 1 (None 1 (0x1))
Photometric 262 (0x106) SHORT: 1 (MinIsBlack 1 (0x1))
ImageDescription 270 (0x10E) ASCII: <?xml version="1.0"?>
StripOffsets 273 (0x111) LONG8: 615
RowsPerStrip 278 (0x116) SHORT: 12133
StripByteCounts 279 (0x117) LONG: 245110866
XResolution 282 (0x11A) RATIONAL: 1 1 (1)
YResolution 283 (0x11B) RATIONAL: 1 1 (1)
ResolutionUnit 296 (0x128) SHORT: 1 (None 1 (0x1))
SampleFormat 339 (0x153) SHORT: 1 (uint 1 (0x1))
用pyometiff打开文件,提示没有OME-XML tags信息
图像数据倒是有,shape不对,传入的图像是20202 * 12133 * 3,写出的数据只有12133 * 20202
我不知道image_scope是否支持OME-TIFF。但是pyometiff出现问题,是因为它依赖的tifffile库存在一个问题:
def is_ome(self) -> bool:
"""Page contains OME-XML in ImageDescription tag."""
if self.index != 0 or not self.description:
return False
return self.description[-4:] == 'OME>' # and [:13] == '<?xml version'
它通过一种非常简单粗暴的方式验证OME-XML是否正确,也就是看图像描述字符串的最后4个字符是否恰好为'OME>'。这种方法显然很不鲁棒,因为本库使用pugixml库生成XML文本,生成的文本最后会多一个换行符,就因为这多出来的一个换行符就被tifffile库认为不是合法的OME-XML……
我用ImageJ打开图像就能正常读入,ImageJ显然正确地识别了带末尾换行符的XML文本。
我上传了一个新版本,理论上应该已经去掉了换行符,你再试试看?
用fiji版本的imageJ可以打开了,看起来像是只写了一个通道,成灰度图了,而且有错乱的情况,
是不是rgbrgbrgb这种顺序的buffer不能直接传写出像素呢,我的生成代码应该有地方没处理对
如果是正常的图片,应该是这样
这是写出的tif文件
https://www.123pan.com/s/IEFUVv-iQb5d
看起来你的实际维度顺序是CXYZ,不是XYCZT。你需要重新排列你的图像维度顺序,必须与创建TIFF时指定的顺序一致。这个操作类似于MATLAB的permute函数,如果你不知道如何用C++实现,可以使用MATLAB生成C++代码,或者上网搜索C++的维度重排算法。本库暂时不能代替你完成这个操作。
但是,你可以使用像素指针
功能,直接取得一个指向磁盘文件的指针。将重排结果直接写入这个指针,可以减少一次拷贝。
维度顺序XYCZT不变,把图像宽度乘以3之后,出来一个拉宽3倍的完整灰度图,是不是说明维度顺序没问题呢
uint16_t 图像宽度 = imageSize[0]*3;
uint16_t 图像高度 = imageSize[1];
uint16_t 图像层数 = 1;
const 颜色 通道颜色[] = { 常用颜色::红色, 常用颜色::绿色, 常用颜色::蓝色 };
wstring wideusername;
for (int i = 0; i < outFilename.length(); ++i)
wideusername += wchar_t(outFilename[i]);
cout << "开始覆盖创建:" << outFilename.c_str() << endl;
IOmeTiff读写器 * const 读写器 =
IOmeTiff读写器::覆盖创建(wideusername.c_str(),
像素类型::UINT8,
图像宽度,
图像高度,
1, 图像层数, 1, 通道颜色, 维度顺序::XYCZT);
读写器->写出像素((uint8_t*)dataPtr);
cout << "写出像素finished" << endl;
delete 读写器;
你创建图像的时候指定的SizeC参数是错误的,你指定了通道颜色有红绿蓝三个,所以SizeC应该是3。
其次,你需要在Fiji的【Edit\Options\ImageJ2】对话框中勾选【Use SCIFIO when opening files (BETA!)】才能正确看到通道颜色。
我不知道你拉宽3倍意义何在,你可能需要重新考虑一下维度顺序的意义。
维度顺序CXYZ:
(R,X0,Y0,Z0)(G,X0,Y0,Z0)(B,X0,Y0,Z0)(R,X1,Y0,Z0)(G,X1,Y0,Z0)(B,X1,Y0,Z0)(R,X0,Y1,Z0)……
维度顺序XYCZ:
(X0,Y0,Z0,R)(X1,Y0,Z0,R)(X0,Y1,Z0,R)(X1,Y1,Z0,R)……(X0,Y0,Z0,G)(X1,Y0,Z0,G)(X0,Y1,Z0,G)(X1,Y1,Z0,G)
我理解我的数据是这样,假设buffer里都是红色的像素点 rgb就是0,0,255
0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255...
我对应不上哪一部分是x,y和z,感觉是缺失这些维度的数据
我的原始数据也是从扫描仪扫出来的小图片,用itk拼接出来的一张大图,大图里的data就是这个buffer,但是图片是没有深度层级,和坐标位置x,y这些信息的,只有三个通道的像素信息,
这种情况还可以使用image5D来写ome-tiff吗
写磁盘快是真的快,固态上700m写了3s,6.74g写了16.2s
X就是宽度,Y就是高度,你只有单层的话就没有Z,C就是RGB。你的维度顺序是CXY,必须改成XYC