请问把byte[]数据重组成图像的方法

weixin_41884234 2018-04-24 01:48:33
加精
我把一个包含多个图像信息的文件,用FileSteam读入缓冲区,并按照指定的格式逐一把图像数据取出,但目前卡在这些数据如何使用上。我从外国网站找到了描述这个数据结构的文件,但他们的书写方式不太理解,希望能有一些window图形编程方面的高手能指教一下。

先介绍下源文件:
1. 这是一个dat格式的文件,是专用格式,里面没有图片格式的关键字或识别码。
2. 文件里主要包含了3个图形组,每个图形组包含了297张图形数据

接下来介绍下外国找到的资料,具体什么编程语言不明。
解释下阅读方法,他这个文件介绍了这个dat文件的数据结构,把dat用filesteam流,按他描述的顺序进行读取和处理,可以正确读出每一个参数的数据。
其中变量后面的.w;.l表示这个变量的长度,例如width.w表示这个变量为2byte,要从流中取2byte的数据。
w=2byte l=4byte b=1byte

Header

unknown.w //不明参数,取出即可,无需使用
width.w
height.w
depthRes.l
paletteFlag.l (bool)//这个值取出后主要用作bool运算

if paletteFlag
paletteEntry.w * 256

dataPos.l //这里取出一个值,表示从文件头开始的偏移值,这个偏移值后就开始是图形数据
imageCount.w //图片组,即开头说到的3

for imageCount
unknown1.l
if unknown1
unknown2.l
//上面这个fos循环主要是把流位置移正确,本身变量含义不用管

frameCount.w
for frameCount
top.w
left.w
bottom.w
right.w
flag.l

if flag & 8 == 0 // hasAlpha
length.l
dataOffset.l

if flag & 4 // hasBase
dataOffset.l
length.l

if flag & 1 // hasDepth
depthType.b //0指WORD / depthRes, 1指BYTE / depthRes, 2指步长  3指填充nearestDist。(看不明白)
val2.w
nearestDist.w
depthOffset.l
depthSize.l

unk2Length.l
if unk2Length
unk2offset.l



Base
Palette
paletteFlag>0的时候
paletteIndex.b * (width * height)


Alpha
-从alpha数据的偏移位置开始
-逐行压缩
rowSize1.l
for height
rowSize2.l
for width * height
data.w //0x7fff 至 555


展開
rowSize = getLong();
for(int i=0; i<height; i++) {
rowSize2 = getLong();
rows[i] = (rowSize2 - rowSize) / 2;
rowSize = rowSize2;
}

for(int y=0; y<height; y++) {
x = 0;
for(int i=0; rows[y]<width; i++) {
data1 = getByte();
data2 = getByte();
for(int j=0; j<((data1 & 7) << 8 | data2); j++) {
data[x++ + y * width] = data1 & 0xf8;
}
}
}

return data;


Depth
1/depthRes 分辨率深度信息

data.w * (ceil(width / depthRes) * ceil(height / depthRes))



最后说说我目前的进展:
我使用他的header,顺利把第0组的297个图片信息读取了出来。但只有这些无法还原图形,望有图形方面知识的专家,能从上图的信息中找出与图形相关的参数或变量,提供一个方法或思路,让我能把这些数据重组成图片。谢谢~

我使用的代码,因为仅考虑读取第0组,所以仅对第一个组的图片进行了遍历取值,没有对3个组都遍历。

//WORD = short LONG = int byte = byte;
//调试用,写死目标文件名
string path = @"C:\test.dat";

//FileStream方式读取文件到缓冲区buff
FileStream test= new FileStream(path, FileMode.Open, FileAccess.Read);
BinaryReader reader = new BinaryReader(test);

//文件头部分,一个文件只有一个文件头
short unknow = reader.ReadInt16();
short width = reader.ReadInt16();//这个貌似不是单个图片的宽度和高度,
short height = reader.ReadInt16();
int depthRes = reader.ReadInt32();
int paletteFlag = reader.ReadInt32();
short[] paletteEntry = new short[256];
if (paletteFlag > 0)
{
for (int pe = 0; pe < 256; pe++) //这里是我解读的,不知道对不对,原文写的是if paletteFlag paletteEntry.w * 256
{
paletteEntry[pe] = reader.ReadInt16();
}
}

int dataPos = reader.ReadInt32(); //文件头偏移值,表示这里开始是图片数据
short imageCount = reader.ReadInt16(); //图形组,值=3

//因为已经知道有297张图片,所以直接建数组来存
short[] top = new short[297];
short[] left = new short[297];
short[] bottom = new short[297];
short[] right = new short[297];
int[] flag = new int[297];
int[] hasAlpha = new int[297];
int[] alpha_legth = new int[297];
int[] alpha_dataOffset = new int[297];
int[] hasBase = new int[297];
int[] base_dataOffset = new int[297];
int[] base_length = new int[297];
int[] hasDepth = new int[297];
byte[] depthType = new byte[297];
short[] val2 = new short[297];
short[] nearestDist = new short[297];
int[] depthOffset = new int[297];
int[] depthSize = new int[297];
int[] unk2Length = new int[297];
int[] unk2Offset = new int[297];

//本来这里要for循环3次,遍历3个组,因为我们只取第一个组,所以取消,直接按顺序读
//unknown变量没有使用到,只是需要按逻辑读取,一面流的位置错误
int unknown1 = reader.ReadInt32();
if (unknown1 > 0)
{
int unknown2 = reader.ReadInt32();
}


short frameCount= reader.ReadInt16(); //每组图片的总数量,这里值为297
for (int n = 0; n < frameCount; n++)
{
top[n] = reader.ReadInt16(); //用着4个点算出来的距离,从值上来看刚好等于单个图片的尺寸
left[n] = reader.ReadInt16();
bottom[n] = reader.ReadInt16();
right[n] = reader.ReadInt16();

flag[n] = reader.ReadInt32(); //unknow point
hasAlpha[n] = flag[n] & 8; // 0:hasAlpha 1:noAlpha
if (hasAlpha[n] == 0)
{
alpha_legth[n] = reader.ReadInt32();
alpha_dataOffset[n] = reader.ReadInt32();
}

hasBase[n] = flag[n] & 4; //0:noBase 1:hasBase
if (hasBase[n] != 0)
{
base_dataOffset[n] = reader.ReadInt32();
base_length[n] = reader.ReadInt32();

}


hasDepth[n] = flag[n] & 1; //0:noDepth 1:hasDepth
if (hasDepth[n] != 0)
{
depthType[n] = reader.ReadByte();//0指WORD / depthRes, 1指BYTE / depthRes, 2指步长  3指填充nearestDist。(这个是网上找到的,具体意思不明)
val2[n] = reader.ReadInt16();
nearestDist[n] = reader.ReadInt16();
depthOffset[n] = reader.ReadInt32();
depthSize[n] = reader.ReadInt32();
}


unk2Length[n] = reader.ReadInt32();
if (unk2Length[n] > 0)
{
unk2Offset[n] = reader.ReadInt32();
}


我用上述代码运行,取出来的数据与网上贴出来的日志比对,可以对得上,证明这个结构可以正确读取。(网上写这个资料的人,已经顺利把数据还原成图像,只是年代久远已经联系不上)

最后提供附件
附件1:如果还原顺利,第[0]张图片应该张这样


附件2:源头dat文件。链接: https://pan.baidu.com/s/1m1XZbHF0MgeBU8g3wdq0Ow 密码: w647
...全文
4017 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
Boom丶Bum 2018-05-08
  • 打赏
  • 举报
回复
我觉得是否适合做程序员不应该靠这个来评价,对于电脑新手而言,对于字体和全角半角符根本就不太了解,也不明白会在程序中造成什么样的错误. 打不打错字是可以练出来的,没有谁说刚接触电脑就可用很熟练的用电脑,都是经过长期的积累和实践的结果.而且打字和键盘上的快捷键什么的,只要愿意学,很快就能学得会. 我觉得是否适合做程序员应该看自己对这方面的热爱和有没有一颗愿意一直踏踏实实一直学下去的心.
weixin_41884234 2018-04-28
  • 打赏
  • 举报
回复
引用 13 楼 zhao4zhong1 的回复:
个人建议楼主趁早转行。 关于自己是否适合编程的很简单的测试: 在报纸或杂志上随便找一段约1000字的文章,在Word中输入一遍。输完后再参考下面答案: A里面有10处以上文字或标点错误 B里面没有文字或标点错误并敢为此跟人打赌 C里面没有文字或标点错误并且字体和排版完全与原稿一致 D打印在半透明的纸上和原稿重叠在一起检查一模一样,且自我感觉很有成就感 A不适合编程(理由:打字准确度偏低、粗心大意) B初级程序员(理由:打字准确度很高、认真细致、自信、理解全角半角概念) C高级程序员(理由:在B的基础上理解字体和排版也是电脑打印的重要因素、但相比D还不够偏执、精益求精、结果可验证) D软件项目经理(理由:能针对项目给出令人信服的细致到极点的需求说明和典型测试用例。用户几乎挑不出毛病。专业!) 如果想从A变成B的话,到我的资源http://download.csdn.net/detail/zhao4zhong1/4084259里面下载“适合程序员的键盘练习”
职业不是程序员,谢谢。我从头到尾都没说自己是做技术的,不知道从哪里下这个判断并且以这个判断来发表和这个问题无关的答案?老师?
赵4老师 2018-04-28
  • 打赏
  • 举报
回复
个人建议楼主趁早转行。 关于自己是否适合编程的很简单的测试: 在报纸或杂志上随便找一段约1000字的文章,在Word中输入一遍。输完后再参考下面答案: A里面有10处以上文字或标点错误 B里面没有文字或标点错误并敢为此跟人打赌 C里面没有文字或标点错误并且字体和排版完全与原稿一致 D打印在半透明的纸上和原稿重叠在一起检查一模一样,且自我感觉很有成就感 A不适合编程(理由:打字准确度偏低、粗心大意) B初级程序员(理由:打字准确度很高、认真细致、自信、理解全角半角概念) C高级程序员(理由:在B的基础上理解字体和排版也是电脑打印的重要因素、但相比D还不够偏执、精益求精、结果可验证) D软件项目经理(理由:能针对项目给出令人信服的细致到极点的需求说明和典型测试用例。用户几乎挑不出毛病。专业!) 如果想从A变成B的话,到我的资源http://download.csdn.net/detail/zhao4zhong1/4084259里面下载“适合程序员的键盘练习”
www_adintr_com 2018-04-28
  • 打赏
  • 举报
回复
你发的第一张图片大小是 193 X 155 日志中显示的图片大小是 374 X 232 日志中第一张图片的区域算出的大小 right - left = 70 - (-95) = 165 bottom - top = 2 - (-143) = 145, 的到的图片大小为 165 X 145 根据描述, Base 的大小为 paletteIndex.b * (width * height), 即 宽度乘以高度 这三组对应的分别是: 193 X 155 = 29915, 374 X 232 = 86768, 165 X 145 = 23925 而你日志中打印出来的 Base 数据大小是: 12256 没一个对得上的, 全是乱的
赵4老师 2018-04-28
  • 打赏
  • 举报
回复
希望你从不打错字起步,先做一个严谨细致的人,再向逻辑思维清晰的码农挺进。
weixin_41884234 2018-04-27
  • 打赏
  • 举报
回复
引用 10 楼 schlafenhamster 的回复:
你那个 图片 有 alpha 有 depth 是 potoshop 的 图片吗 ?

应该不是,应该是一个bmp格式的位图文件。我再上传一个例子,图数和尺寸都小一点,看能不能有助于降低分析难度

链接:https://pan.baidu.com/s/1_rjanlY6EpYvZWp2hfFV2w 密码:cceu

这个dat里有3组图片,每组8张,其中第一组,即imageCount[0]的图片是一个路牌,如果格式正确,第1组第1、2张图片应该长这样



schlafenhamster 2018-04-27
  • 打赏
  • 举报
回复
你那个 图片 有 alpha 有 depth 是 potoshop 的 图片吗 ?
weixin_41884234 2018-04-27
  • 打赏
  • 举报
回复
还有其他大神有方法吗
weixin_41884234 2018-04-24
  • 打赏
  • 举报
回复
这个日志是网上那个人贴出来的,最开始我就是用最粗暴的方法去核对他提供的数据结构是否正确。逐个数据取出来和他日志进行比对

weixin_41884234 2018-04-24
  • 打赏
  • 举报
回复
引用 2 楼 hhhh63 的回复:
以下是我把CT数据转换为图像的实例,256色,用CImage类 CImage m_cimage;
	if( m_cimage.IsNull() )
	{
		m_cimage.Create( imgw4, -imgh-1, 8 );	// 负高度表示原点在左上角,img.GetBits(); 得到数据区的起点。	// 20150310 imgw 改为imgw4 加宽的图像
		RGBQUAD * pp = (RGBQUAD*)(theApp.palbuffer + 8 + sizeof(UINT)*2 /*+ (256*4+8)*3*/);
		m_cimage.SetColorTable( 0, 256, pp );
	}

	LPBYTE p = (LPBYTE)m_cimage.GetBits();
	LPWORD p2 = pimgdata1;
	//const int w2 = (imgw + 0x3) & ~0x3;	//?? 实际宽度是4的倍数?是否与操作系统或硬件有关。
	WORD threshold = tbg_threshold ? roundint( tbg_threshold * kt * 0.95 ) : temperaturemin;	// 背景和人体分界点
	//ASSERT( !tbg_threshold );
	int dd = temperaturemax - threshold;	// 窗宽
	if( dd < roundint(5 * kt) )		// 设置温差最小值为10度,防止除零、未初始化等等。
		dd = roundint(5 * kt);
	for( int i = 0; i < imgh; i++ ){
		int j = 0;
		for( ; j < imgw; j++ )
		{
			int w = (*p2++ - threshold) * 255 / dd;
			if( w < 0 ) w = 0;
			if( w > 255 ) w = 255;
			*p++ = (BYTE)w;
		}
		for( ; j < imgw4; j++, p++ );	//?? 补齐多余的宽度?
	}

	m_cimage.StretchBlt( hDestDC, drc, orc, dwRop );
谢谢~我琢磨下看能不能应用
weixin_41884234 2018-04-24
  • 打赏
  • 举报
回复
引用 1 楼 schlafenhamster 的回复:
请 把 第[0]张图片 的数据 和 有关信息 用 HexWin 转成 text 文件
链接: https://pan.baidu.com/s/1VxnuW0ad7fbz3SDnFtZl5g 密码: 1jus 压缩包包含了alpha,base,depth。但是一开始的palette没有,主要是对palette不了解,我是用256容量的数组去取了值,取出来的值如下 https://shimo.im/sheet/Pe3UEuwKWosDdEsv/ 点击链接查看「paletteEntry[256]」
hhhh63 2018-04-24
  • 打赏
  • 举报
回复
以下是我把CT数据转换为图像的实例,256色,用CImage类 CImage m_cimage;
	if( m_cimage.IsNull() )
	{
		m_cimage.Create( imgw4, -imgh-1, 8 );	// 负高度表示原点在左上角,img.GetBits(); 得到数据区的起点。	// 20150310 imgw 改为imgw4 加宽的图像
		RGBQUAD * pp = (RGBQUAD*)(theApp.palbuffer + 8 + sizeof(UINT)*2 /*+ (256*4+8)*3*/);
		m_cimage.SetColorTable( 0, 256, pp );
	}

	LPBYTE p = (LPBYTE)m_cimage.GetBits();
	LPWORD p2 = pimgdata1;
	//const int w2 = (imgw + 0x3) & ~0x3;	//?? 实际宽度是4的倍数?是否与操作系统或硬件有关。
	WORD threshold = tbg_threshold ? roundint( tbg_threshold * kt * 0.95 ) : temperaturemin;	// 背景和人体分界点
	//ASSERT( !tbg_threshold );
	int dd = temperaturemax - threshold;	// 窗宽
	if( dd < roundint(5 * kt) )		// 设置温差最小值为10度,防止除零、未初始化等等。
		dd = roundint(5 * kt);
	for( int i = 0; i < imgh; i++ ){
		int j = 0;
		for( ; j < imgw; j++ )
		{
			int w = (*p2++ - threshold) * 255 / dd;
			if( w < 0 ) w = 0;
			if( w > 255 ) w = 255;
			*p++ = (BYTE)w;
		}
		for( ; j < imgw4; j++, p++ );	//?? 补齐多余的宽度?
	}

	m_cimage.StretchBlt( hDestDC, drc, orc, dwRop );
schlafenhamster 2018-04-24
  • 打赏
  • 举报
回复
请 把 第[0]张图片 的数据 和 有关信息 用 HexWin 转成 text 文件
weixin_41884234 2018-04-24
  • 打赏
  • 举报
回复
引用 6 楼 schlafenhamster 的回复:
说明 “外国找到的资料” 的 出处
是外国一个校园网论坛的技术板块,得该学校的内网ip才能访问。我估计五一后会去那边。。如果这段时间没有啥进展,我到时去到那边把他原帖子再拷贝一下,原贴是英文的,上面部分是我翻译过的,也有可能是翻译不到位导致理解有偏差
schlafenhamster 2018-04-24
  • 打赏
  • 举报
回复
说明 “外国找到的资料” 的 出处

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧