2016年4月26日 星期二

Visual Studio 連結 OpenCV (Visual Studio 2013+openCV 2.0為例)

基本上我習慣把各個版本的OpenCV 放在一個目錄SDK裡,
方便日後可以適用切換各個版本的Library。


以最普通的Win32 Console Application 專案為例。






include 最常用的 "cv.h" 與 "highgui.h",出現紅線表示尚有連結路徑尚未設定。
主要幾個重要步驟:
[Configuration Properties] VC++ Directories 
[Include Directories] 位置指到 OpenCV2.0\include\opnecv
[Library Directories] 位置指到 OpenCV2.0\lib\Release (Debug狀態就設到Debug)
[Library Directories] 位置指到 OpenCV2.0\bin\Release (Debug狀態就設到Debug)

最後在[Linker] [Input] 塞入你有用的到的 Library
※Debug狀態就要相對塞入 cv200d.lib cxcore200d.lib highgui200d.lib
※Release狀態就要相對塞入 cv200.lib cxcore200.lib highgui200.lib (沒有"d")


2016年3月2日 星期三

[Visual studio] 如何在 Visual studio 倒出 assembler code

在寸土寸金追求效能的Embedded system工作環境,時常會有個習慣,就是在compile之後,去查看將自己的C code與make出來的assembly code 是否達到自己預期的效能。在gcc compile裡有dump指令,然而在Visual studio又如何dump出assembly code呢?

其實在Visual studio 很早的版本裡就有加入的這個功能,至於從何版本開始我並沒有實際考證,本篇則我試著以Visual studio 2005, 2015為範例將自己的code輸出assembly code。

[2005]
step 1.目標cpp檔點右鍵選 [Properties]




step 2.[C/C++] → [Output Files] →[Assembler Output] →選擇你要的選項
[Assembler with source code] 將輸出Assembler 並區段附上你的c code比較好對應




step 3.可在檔案輸出資料夾看到一個檔案類型名稱為Assembler Source即是
















[2015] 由於我2015正好是中文版的,來個中文步驟
步驟 1.目標cpp檔點右鍵選 [屬性]















步驟 2.選取[C/C++] [組合語言輸出][組譯碼、機器碼和原始程式碼]


步驟3與2005一樣可在輸出資料夾裡看到組語檔案。
以上簡單的分享有問題在留言

2016年2月28日 星期日

[影像處理] Image segmentation 切割記憶體

影像說穿了就是一連串的(BYTE)資料,
本篇提供了快速的記憶體切割技巧,利用memcpy以避免一個pixel一個pixel去拜訪的動作。
有做過embed system的朋友應該曉得,拜訪記憶體是一件很耗時間的事情,故在此分享。
※本篇程式碼只適用單通道的灰階影像(BYTE 0~255)

Image segmantation 切割記憶體coding邏輯原理如下:
可想像使用小畫家時所使用的"矩形選取"然後擷取區塊。
矩形的右上角即為(startX,startY)矩形的寬高即為程式的seg_w、seg_h。



typedef unsigned char       BYTE;
void SegMemery(int startX,int startY,BYTE* src,BYTE* dst,int src_w,int seg_h,int seg_w)
{
   BYTE *Index_Seg,*Index;
   int SegLenth,IndexLenth;
   int start = startY, end = startY + seg_h;
   /////////////////////////////////
   SegLenth = seg_w*sizeof(BYTE);
   IndexLenth = src_w*sizeof(BYTE); 
   /////////////////////////////////
   Index_Seg = dst;
   Index =src+ (start *  src_w +startX)*sizeof(BYTE);
   for(int i = start; i <  end; i++)
   {
    memcpy(Index_Seg,Index , seg_w); 
    Index_Seg += SegLenth;
    Index += IndexLenth; 
   } 
}



以上即為影像切割之程式邏輯原理,
有影像切割就有影像貼上,memcpy邏輯相反而已。
若有疑問歡迎寫信,留言告知。





2016年2月27日 星期六

[影像處理] 用C 讀取 .raw影像檔

RawData 顧名思義,只有純Data檔案"不同於"其他影像檔案格式(BMP,jpg等)具有檔頭資訊,
故一開始拿到RawData是無法得知它的寬高,除非事先告知影像寬高資訊,
但若是只是單單只想靠C將.raw檔倒入一個array只須參考下列程式碼:

 typedef unsigned char       BYTE;

 char cPath[100];
 BYTE Image[640*480]; //image size buffer
 sprintf(cPath,"/Storage Card/test.raw");

 FILE *hFileTmp;
 hFileTmp = fopen(cPath, "rb");
 if(hFileTmp==NULL)
 {
        fclose(hFileTmp);
        return true;
 }
 fread(Image, sizeof(BYTE),640*480, hFileTmp);

備註:
我們可以由檔案右鍵內容得知資料長度,
並且可以加以推測目前主流的解析度:
640x480 = 307200
640x400 = 256000
1280x800 = 1024000


office 365 安裝步驟

現在的office 365不同以往,傳統往往一次要下載一大包的iso檔,
而現在的office 365有點像遊戲一樣,要先官網登入帳號後,
下載大小不大的安裝檔並進行後續的下載動作。

office 365 官網
https://products.office.com/zh-tw/office-365-personal



選擇官網內的登入選項,選擇自己帳號的種類即可。















 會載到一個Setup.X86.zh-TW開頭(大小約3M)的檔案。



點選Setup.X86.zh-TW開頭的檔案,即可下載安裝。
最後安裝完,記得點選Word or Exel or Prowerpoint ..任意即它程式。
進行登入認證即可。









2016年2月26日 星期五

[影像處理] C程式 Bayer conversion 與原理介紹

隨著IOT物聯網與AR擴增實境的興起,不少東西都會使用到camera sensor,往往去連結 camera sensor之後,會發現所拿到sensor raw data並非windows圖片檔案格式的樣子。Bayer conversion是現在消費性電子最為普通的,透過Bayer color filter可將光分成紅綠藍,並且打在各個pixel上。利用這樣規律pattern廣泛的打在sensor上,雖說每個pixel取到的RGB物理意義可能會有不同,但透過這樣的pattern鄰近的RGB色彩反推,也可得到趨近於我們肉眼想看的影像。














Q1.有些人可能會問,這樣交錯算出的影像未必是最真實的,為什麼不採用每個點去接收RGB然後得出一個影像?
A1:基於成本考量,除非很特殊的光學設計,不然在一個面積有限sensor面積裡同時感測出不同顏色的光是有困難的,總不能在sensor上面裝個機械的濾淨閘快速的替換濾淨,利用高frame rate讓RGB影像幾乎是同一個時間點,當然這種設計相對難度高且成本也會高出許多。所以近代的消費性sensor幾乎都會提出這樣交錯有規則性的pattern感測顏色。

Q2.為什麼Bayer pattern 綠色的點較多?
A2:有一句話叫做科技來自於人性,camera sensor拍出來的影像始終是要給消費者看的,所以才會有I phone拍出來的影像怎麼比小米好的感覺,一方面是sensor的成本反映出的sensitivity不同,另一方面就是影像教調的部分。回到原來的問題,經科學證實人眼對於綠色較為敏感,故綠色在Bayer pattern的設計也有考慮到這點,採取2x2綠色佔較高權重的RGGB、BGGR,而各家大廠為了去彌補這樣的問題,有的在sensor接收過後的影像做調教(各種Interpolation色彩轉換),有的則是在sensor濾鏡上做設計,配合各家色彩轉換的強項提出屬於各家廠商特有的pattern 濾鏡。



[補記 2016/07/16]
最近無意間在網頁上瀏覽到小米5的簡介,簡介中附錄了一張小米5照相機的結構圖,
實在畫的太好非常適合踏入這個領域初學者示意講解,
(以下圖檔純為教學解釋用,並無其餘商業用途,版權為小米所有)















以上為一個現代相機模組的示意圖,由左而右為多片鏡片+彩色濾淨組合成,
其次為它的外殼,藍色面板為camera sensor,可透過camera sensor 取的Raw data,
故上圖示意camera sensor後面有一塊RGGB的圖案,即為本章節介紹 Color pattern的轉換,
最後後面有個ISP(Image Signal Processing),專門負責對這顆camera sensor下指令,
來做曝光(AE) 對焦(AG) 白平衡(AWE)與色彩平衡的控制。
對於現代消費性電子來說,近幾代camera sensor大廠都已提供的這樣外加ISP模組架構流程做應用,甚至有些camera sensor本身就不提供3A功能,純粹給應用端自行調配設計。
這也就是上面我說即使手機使用一樣的sensor,但為什麼拍出來會有不一樣的感覺。


此篇提供了一個簡單的3x3 Interpolation協助Bayer pattern做色彩轉換,大致可分為中心點為R與B兩種,與中心點為綠色不同周遭不同排列的G1、G2兩種。








透過分析可將Bayer pattern 橫向縱向積偶排列組合分成四種,正好符合以上3x3interpolation的核心原則,但建議coding的人還是要注意一下,sensor左上角的起始是RGGB or BGGR? 若情況反過來有可能就會做出一格一格的馬賽克效果。
#define B_OFFSET    0
#define G_OFFSET    1
#define R_OFFSET    2
#define ODD(i)      ((i)&1)
#define EVEN(i)     (!((i)&1))

void BayerConversion(unsigned char *rawData, unsigned char *dst, int dst_w, int dst_h, int rawData_w)
{
    int x,y;
    int yWidth=0, yRawWidth=0, ym1RawWidth = 0, yp1RawWidth;
    int pix;
    int Red,Green,Blue;
    memset(dst,0,sizeof(unsigned char)*dst_w*dst_h*3);
    for (y = 1; y < dst_h - 1; y++)
    {
        yWidth += dst_w;
        yRawWidth += rawData_w;
        ym1RawWidth = yRawWidth - rawData_w;
        yp1RawWidth = yRawWidth + rawData_w;
        for (x = 1; x < dst_w - 1; x++)
        {
            pix = ((x+yWidth)<<2);
            if (ODD(y))
                if (ODD(x))
                {   
                    Blue  = ((rawData[x-1+  yRawWidth] + 
                              rawData[x+1+  yRawWidth]) >> 1);
                    Green =   rawData[x  +  yRawWidth];
                    Red   = ((rawData[x  +ym1RawWidth] + 
                              rawData[x  +yp1RawWidth]) >> 1);
                }
                else
                {   // ODD(y) EVEN(x)
                    Blue  =   rawData[x  +  yRawWidth];
                    Green = ((rawData[x-1+  yRawWidth] + 
                              rawData[x+1+  yRawWidth] + 
                              rawData[x  +ym1RawWidth] + 
                              rawData[x  +yp1RawWidth]) >> 2);
                    Red   = ((rawData[x-1+ym1RawWidth] +
                              rawData[x+1+ym1RawWidth] +
                              rawData[x-1+yp1RawWidth] +
                              rawData[x+1+yp1RawWidth]) >> 2);
                }
            else
                if (ODD(x))
                {   // EVEN(y) ODD(x)
                    Blue  = ((rawData[x-1+ym1RawWidth] +
                              rawData[x+1+ym1RawWidth] +
                              rawData[x-1+yp1RawWidth] +
                              rawData[x+1+yp1RawWidth]) >> 2);
                    Green = ((rawData[x-1+  yRawWidth] +
                              rawData[x+1+  yRawWidth] +
                              rawData[x  +ym1RawWidth] +
                              rawData[x  +yp1RawWidth]) >> 2);
                    Red   =   rawData[x  +  yRawWidth];
                }
                else
                {   //EVEN(y) EVEN(x)
                    Blue  = ((rawData[x  +ym1RawWidth] +
                              rawData[x  +yp1RawWidth]) >> 1);
                    Green =   rawData[x  +  yRawWidth];
                    Red   = ((rawData[x-1+  yRawWidth] +
                              rawData[x+1+  yRawWidth]) >> 1);
                }
     dst[pix+B_OFFSET] = Red;
     dst[pix+G_OFFSET] = Green;
     dst[pix+G_OFFSET] = Blue;
        }
    }
}