作者hrs113355 (小分分)
看板b97902HW
标题[心得] 单班计程补血包
时间Mon Dec 8 23:20:40 2008
不知道现在PO还来得及吗Orz
首先,先看清楚题目的意思,题目的意思是要我们读入多个bmp档,
对於
每次测试,都会有一到多组的bmp档,
因此会输入一到多组的档名
所以档名请大家
用while/for去读取,才能读取很多次
另外,请千万要注意
档名可能会有space
也
请记得判断输入的档名,其档案不存在的情况。
(通常这会让你的程式当掉了!>"< 原因:使用到不该用的记忆体)
bmp档的一开头会有一个
14 byte的File Header和一个40 byte的DIB Header,
之後就是存图案的各个pixel资料。 (像素)
读入的部分用
fread ()和 fseek() 函式帮忙
fread的用法是
fread (读入资料的指标, 资料的大小, 资料个数, 串流)
fseek的用法是
fseek (串流, 移动的offset, 起始位置)
详细的用法,就请大家参考 averangeall大神的那篇文章
^^(有挪台喔 科科)
那读入的话,你可以写一个专门存bmp header的struct
比如说
struct bmp{
unsigned short int magic;
....
}
补充:
下面会提到padding,就是因为我们现在做struct的时候,compiler会帮我们padding
所以要关掉,不然我们的struct也会被补上padding (下面会解释padding是啥)
特别感谢几米肯提醒,刚刚忘记写上来了
这是一个struct,为了把padding关掉,我们要加上__attribute__ ((packed))
如下
typedef struct bmppoint
{
unsigned char blue;
unsigned char green;
unsigned char red;
}
__attribute__ ((packed)) BMPPoint;
要放哪些东西可以参考维基上的资料。 (资料型态和资料的内容)
然後再
用fread一次把那整个struct抓进来,如果讲到这边还是不太懂
还是请您参考一下 averangeall大神的那篇文章
^^(有挪台喔 科科)
抓完之後就是要判断档案的真伪了,
没错,就是像Foxy一样,
有假档= =+
那要怎麽判断呢,根据维基上的说明,bmp档的前两个byte会记下一个magic number
那个东西是"BM",换成十进位是19778
但是通常事情不会像我们想的只有这麽简单,所以请像Tips所说的,
尽你的全力找出Header里面不合理的事:
比如说整个档案size应该满足什麽条件?
长、宽、横向解析度、纵向解析度应该满足什麽条件? (当然可能还有其他要注意的条件)
最需要注意的是image size (the size of raw bmp data)
刚刚说过,Header存完之後,
接下来的bmp档就是一个一个点(pixel)的资料
你可以把他想成二维阵列的样子,但是不是。
例如楼下这个图
0 1 2 3 4
3 ■
■■■■
2 ■
■■■■
1 ■
■■■■
0 ■
■■
■■
请注意,他的y是倒过来的,可是我们算座标的时候也是从下往上算的,
所以不需要特别处理他。
那这个资料的储存形式就是
■
■■
■■(padding)■
■■■■(padding)■
■■■■(padding)■
■■■■(padding)
(每一行结束都会加上padding)
(255, 255, 255)(255, 0, 0)(255, 255, 255)(255, 0, 0)(255, 255, 255)(padding)
(255, 255, 255)(255, 0, 0)(255, 0, 0)(255, 0, 0)(255, 255, 255)(padding)
(255, 255, 255)(255, 0, 0)(0, 0, 255)(0, 255, 0)(0, 255, 0)(padding)
(255, 255, 255)(255, 0, 0)(255, 0, 0)(255, 0, 0)(255, 255, 255)(padding)
其中 (xxx, xxx, xxx)就是三原色的调配 => (蓝, 绿, 红) 数值大小从 0 ~ 255
这个时候你就会问padding是什麽了,padding是为了让structure资料在写入的时候
补齐为4 byte的倍用的。
像上面的例子,一个格子存一个颜色用到3 byte,一行有五个格子
所以用到了 3 * 5 = 15 byte,可是我们要补齐到4 byte的倍数呀!
所以就找最接近的 16 byte,16 - 15 = 1,所以我们要补上1 byte
所以这里的padding就是一个byte的东西,但内容是什麽不重要。
这样你就发现了,
padding大小会随着图一行的宽度改变,
所以
请自行利用取余数技巧计算。
刚刚说到一半的image size (the size of raw bmp data)是什麽呢
就是这些像素资料的大小,像刚刚这个5x4的例子里
占用空间 有四行
image size = (5 * 3 + 1) * 4 = 64
padding
但是要特别注意的是,
有时候他也可以不写!!! 也就是说
image size = (宽 * 3 + padding) * 高 or 0
维基里有写 "Note: The image size field can be 0 for BI_RGB bitmaps."
这个真的超心机的,要
感谢Logan的提醒
刚刚讲的都是判断档案是否正常的部分
接下来就是
利用读出来的长、宽资料去跑回圈读像素的资料 ((xxx, xxx, xxx)的那个)
资料的排列方式刚刚说过了,所以请爱用for回圈 XD
然後要
记得每一横行读完要考虑padding的问题
每一次在读像素的资料的时候,
各个点的密度是亮度的平均,比如说那个点是 (1, 2, 3)
那密度就是 (1 + 2 + 3) / 3
那个点的
质量 = 密度 / (横向解析度 * 纵向解析度)
如果要算质心的话 x和y要分开算
要先
分别把每个点的 {质量 * (那个点和中心的相对位置) / 解析度} 加起来
这个讲起来有点复杂
举个例子好了
假设我现在读到(5, 6)这个点,但整张图的长宽是 10 * 20
所以我们知道原点应该是 ((10 - 1) / 2, (20 - 1) / 2) (要减一是因为从0开始)
= (4.5, 9.5)
所以就把 质量 * (5 - 4.5) / x的解析度 <- x的部分
质量 * (6 - 9.5) / y的解析度 <- y的部分
把他们累加起来
最後再除以总质量,这就是质心 (记得x, y要分开算)
那如果只是把质量累加起来,那就是总质量
所以这是单张图的作法
多张图只要把很多单张图累加,再除以有效图数,就是答案了
比如说有四张图输入,但只有3张是有效的图
那最後就是把那3张的质量/质心x座标/质心y座标 加起来除以3
今天好不容易找到卡住我一个星期的脑残点,也希望大家可以赶快杀死刚弹,
所以赶快跑上来PO一下
但是我打字好慢,对不起Q___Q"
还没AC的大家加油!
--
你今天XD了吗?
欢迎到 叉滴小站
telnet://XDbbs.twbbs.org
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 140.112.7.59
1F:推 vdm9999:神!神!神!神!神!神!神!神!神!神!神!神!神!神!神!神!神!神! 12/08 23:22
2F:推 benck:有神快拜 12/08 23:25
3F:推 crystal0825:(跪) m(_"_)m 12/08 23:27
4F:推 purplebleed:这篇文章.....如果在礼拜四出来就好了........ 12/08 23:50
5F:→ hrs113355:sorry >"< 12/08 23:56
6F:推 jimmyken793:读struct会有padding bytes 要用#pragma pack(1)关掉 12/08 23:58
7F:推 purplebleed:楼上说的好!!!!当时我就觉得那个很奇妙~~ 12/09 00:13
8F:推 averangeall:这教学文太强大了 虽然我双班看不懂… 12/09 01:57
9F:→ averangeall:还有我帐号前面不用挪什麽台… 12/09 01:57
10F:推 benck:一定要的啊 有神快拜 12/09 09:29
11F:推 ldldldldldld: averangeall应该要换行打以示尊敬 12/09 10:51
12F:推 lmr3796: 12/09 16:27
13F:→ lmr3796:averangeall 大神快拜! 12/09 16:28
※ 编辑: hrs113355 来自: 140.112.199.250 (12/09 17:57)
14F:推 qq123789:拜 12/09 19:10
15F:→ qq123789:averangeall 神! 12/09 19:10