作者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