2016年9月8日 星期四

C++ 如何開啟 RAW 圖檔 [OpenRAW 2.31]

C++ 如何開啟 RAW 圖檔 [OpenRAW 2.31]

解決的問題:
  • 用什麼型態儲存更適合
  • 控制開檔、讀檔、存檔與匯出檔案
  • 繪製簡易的數值統計直方圖
  • 使用 [] 下標存取 class 宣告的物件
  • 方法 引入參數簡化
  • 更有效率的取得遮罩

OpenRAW 2.31 refrence

如何引入使用
標頭僅需引入 #include "OpenRAW"
使用時須使用命名空間 namespace imr
可在標頭引入 using namespace imr;
typedef unsigned char imch;
typedef size_t imint;

namespace imr{
    class ImrSize{
    public:
        ImrSize(imint y, imint x);
        imint width;
        imint high;
    };

    class ImrCoor{
    public:
        ImrCoor(int y, int x);
        int y;
        int x;
    };

    class ImrMask{
    public:
        ImrMask(ImrSize masksize);
    private:
        vector<imch> mask;
    };

    class imgraw {
    public:
        imgraw(ImrSize size);
    private:
        vector<imch> img_data;
    };
};

各項類別屬性與建構說明


ImrSize 畫布大小

ImrSize 用來描述畫布畫布大小
大小可在建構時設置
如,設置一個256x256大小的畫布
ImrSize size(256,256);
使用時可使用公開變數
size.widthsize.high
型態為 size_t
某些情況可需要轉態
for (int i=0; i<=(int)size.high, ++i)

ImrCoor 座標位置

ImrCoor 用來描述座標位置
座標可在建構時設置
如,設置一個(0,0)的座標
ImrCoor coor(0,0);
使用時可使用公開變數
size.ysize.x
型態為 int

重載

ImrCoor 提供基本的加減乘除運算子
ImrCoor a(1,2), b(3,4), c;
c = a+b;
C則為(4,6)依此類推

ImrMask 遮罩陣列

ImrMask 用來儲存遮罩陣列
使用時需再主程式宣告,並接住(複製)
方法產生的類別,即可使用。
ImrMask mask = img.getMask();
由於僅是接住方法產生的陣列
故不需建構任何資訊(由方法建構)
方法用法請參考該類別說明欄位
使用時可直接使用[下標]存取指標陣列
cout << mask[0] << endl;
mask[0] = 1;
型態為unsigned char*
雖然為動態陣列,不過會智能解構
不必擔心主程式接住後記憶體釋放問題
因為是動態陣列,主程式用複製的方式
只複製指標並不會拖垮效能
不過讀取的時候那仍然是複製數值
盡可能使用 maskVal() 取代

方法

imch & at2d(size_t y, size_t x);

以二維的方式存取位置(y,x)的遮罩
cout << mask.at2d(0,0);
mask.at2d(0,0) = 0;

void sort(size_t len, size_t start);

插入排序遮罩大小,由小到大
mask.sort(); 排序全部
其中可以自由指定那些需要排序
sort(len, start);
比如說一共有4個我要排序中間兩個
長度是2,從mask[1]開始排序
mask.sort(2,1);

imgraw OpenRAW主要類別

imgraw 用來儲存RAW圖檔
在建構時需設置圖檔大小
建構參數是 imgraw(ImrSize) 類別
如,設置一個256x256大小的圖檔
ImrSize size(256,256);
imgraw img(size);
你也可以一起設置
imgraw img(ImrSize(256,256));
設置錯誤的圖檔大小,基於RAW檔特性
程式是無法辨別並自動修正的
可能會產生不可預知的錯誤
使用時可直接使用[下標]存取圖檔資訊
cout << img[0] << endl;
img[0] = 1;
型態為vector<unsigned char>
注意因為型態是 unsigned char
如果超出255將會從0開始計算
修正方式請在處理時轉為其他型態
img[0] = 127;
double temp;
temp = (double)img[0] + (double)255;

if (temp > 255){
    temp=255;
}

img[0] = (unsigned char)temp;

方法

typedef unsigned char imch;
typedef size_t imint;

void read(string filename);

將檔案與主程式放到同一個位置
img.read("File name");
即可將圖檔讀入

void write(string filename);

img.write("File name");
填入輸出的檔名,通常會在圖像處理完畢後輸出

imch & at2d(size_t y, size_t x);

以二維的方式存取圖檔資訊
cout << img.at2d(y, x) << endl;
img.at2d(y, x)=img.at2d(y, x)+10;

void resize_canvas(ImrSize size);

重新定義畫布大小
img.resize_canvas(ImrSize(high, width))

imint w();

獲得寬
img.w();

imint h();

獲得高
img.h();

void pri_htg(string title);

印出直方圖
img.pri_htg("title name");

void setMaskSize(ImrSize masksize);

設定遮罩大小,使用getMask()前須事先指定
img.setMaskSize(ImrSize(3,3));

imch maskVal(ImrCoor ori, ImrCoor mas, ImrCoor shi);

取得遮罩數據
遮罩會自動檢查邊界,如果遇到邊界無法取值,自動補上邊界數值

使用說明
ImrCoor ori();
對應原圖的點
ImrCoor mas();
遮罩二維位置
ImrCoor shi();
偏移位置(可省略預設 -1,-1)
假設
ori(1,1),
mas(2,2),
shi(-1,-1),
原圖(5x5)
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 

遮罩參考點 ori(1,1)
○ ○ ○ ○ ○ 
○ ● ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 

加上位移 shi(-1,-1)
● ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 

放大這個部分 
● ● ● ○ ○ 
● ● ● ○ ○ 
● ● ● ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 

取 mas(2,2)
● ● ● 
● ● ● 
● ● ○ 

img.maskVal(ImrCoor(1,1), ImrCoor(2,2));
可得 [ 若shi留空,預設是shi(-1,-1) ]
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ● ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○

ImrMask getMask(ImrCoor ori, ImrCoor shi);

取得遮罩陣列(一維)
需先設置遮罩大小 img,setMaskSize(ImrSize(3,3));
點會複製到動態陣列上,除非有要排序,否則會比較花費時間
// 設定遮罩
img.setMaskSize(ImrSize(4,4));
// 取得Mask陣列及排續 getMask(原點位置)
ImrMask mask = img.getMask(ImrCoor(2,2));

cout << endl<< "setMaskSize" << endl;
for (int j = 0, c = 0; j < 4; ++j){
    for (int i = 0; i < 4; ++i, c++){
        cout << (int)mask[c] << " ";
        // cout << mask.at2d(j,i);
    }cout << endl;
}
原圖(5x5)
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 

對應原圖的點
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ● ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 

偏移位置 shi(-1,-1)
[ 若shi留空,預設是shi(-1,-1) ]
○ ○ ○ ○ ○ 
○ ● ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 
○ ○ ○ ○ ○ 

獲得(4x4)
○ ○ ○ ○ ○ 
○ ● ● ● ● 
○ ● ● ● ●  
○ ● ● ● ●  
○ ● ● ● ●

2016年9月1日 星期四

動態陣列,注意事項與二維一次性宣告方法

動態陣列,注意事項與二維一次性宣告方法

tags:C++

delete 與 delete [] 差異

兩者都會呼叫解構函式,差別在於
後者只會呼叫開頭指標的解構函式
簡單來說今天你配置了arr[n]的動態陣列
如果你僅使用 delete 那只會解構 arr[0]
後面全部都不會被解到,可怕的是
這並不意味不能編譯與執行。
為了避免這種情況,記得養好習慣
聽起來很複雜,用一句話概括
方括配方括

這裡如果還不夠明白,簡單測試一下就能馬上了解了
#include <iostream>
class cls{
public:
    cls(){ std::cout << "constructor" << std::endl; }
    ~cls(){ std::cout << "destructor" << std::endl; }
};
int main(){
    cls* p = new cls[5];
    delete [] p;
    return 0;
}

釋放的指標最好手動指向空指標

上面我們可以知道 new[] 必須搭配 delete []
這裡還有一個小問題,你可以嘗試著把上方的代碼
印出釋放後的指標,你會發現指標沒有指向 0
這不是太大問題,但是如果造成問題了(肯定會有的
只是用到機率不大),應該不容易被找到問題點
養成習慣最好在釋放後手動指向空指標
空指標這裡簡單的敘述什麼該用什麼
  • C 使用 NULL
  • C++ 使用 0
  • c++11 使用 nullptr
千萬不要因為看起來不重要,且實際實際執行
時確實無法直接看出差別,就忽視了或偷懶

如果你不想 delete 那麼多

可以算出長度,一次宣告出全部
下標仍然可以使用,直接加上就好
void** new2d(int h, int w, int size){
    register int i;
    void **p;
    p = (void**)new char[h*sizeof(void*) + h*w*size];
    for(i = 0; i < h; i++)
        p[i] = ((char *)(p + h)) + i*w*size; 
    return p;
}
因此就可以用這 function 動態建立二維陣列
data = (int **)new2d(data_height, data_width, sizeof(int));

可以把他整合到Macro
在程式前頭增加
#define NEW2D(H, W, TYPE) (TYPE **)new2d(H, W, sizeof(TYPE))
便可簡化剛剛動態配置二維陣列寫法
data = NEW2D(data_height, data_width, int);

參考資料

  1. [問題] 指標 直接存取與使用下標存取 差異
    https://www.ptt.cc/bbs/C_and_CPP/M.1472632682.A.DE7.html
  2. 關於指標的new、delete、NULL的觀念問題
    http://www.programmer-club.com.tw/showSameTitleN/c/37427.html
  3. Re: [心得] 空指標常數(null pointer constant)
    https://www.ptt.cc/bbs/C_and_CPP/M.1461824349.A.B47.html

2016年8月29日 星期一

Git for windwos [修改 預設 工作 目錄] 與 [自訂命令]

Git for windwos
  1. 如果你的工作目錄固定,又或是放在D槽,修改預設目錄可以省下不少重複動作
  2. 有一些比較長的指令也可以利用 alias 縮短成比較簡單的

修改初始位置

到這個目錄底下修改 bash.bashrc
C:\Program Files\Git\etc
必須使用管理員權限才能修改
或者先複製到桌面修改完畢覆蓋回去
在最底下加入自己想要的路徑
(我是指定到OneDrive內)
cd OneDrive\\KUAS-Hw
注意斜線是兩條

alias

一樣在這個文件最底下加入你要的命令
alias add=’git add -i’
我是把 git add -i 改成 add
所以我只要輸入add就可以加入檔案了

2016年8月28日 星期日

指標的基本用法

指標

基本概念
  • 符號意義
副程式
  • 為何副程式必須導入指標
  • 副程式引入處指標與陣列不同
  • 如何從副程式得到指標長度
  • 間接定址與直接定址
  • 為何需要指標的指標
 指標類型
  • 指標的指標
  • 結構指標
  • 虛無指標
下周分享內容:如何有效率的編程

基本概念

符號意義

記住兩句話 &找地址 *找數值  
int i=1 程式初始化配置記憶體
給變數i使用並在裡面儲存數值1
可以透過 &i 查找記憶體地址
int* p=&i 創建一個指標,並告知
編譯器這個用來儲存儲存整數,再來存入
i 的地址
可以透過 *i 查找記憶體地址內的數值
關於指標的創建,請記住這句話
告知編譯器這個用來儲存儲存整數
後續會繼續討論,這裡先討論兩個區別
int* iint *i 有什麼區別呢
在編譯器內他們是等價的,但建議使用前者
的方式宣告,更容易閱讀,可以想像
把他們當成另一個型態 int*
這樣更容易閱讀對吧XDD
那什麼時候才需要用到把星號放到後面呢?
int* i, j; 你覺得後面的j是什麼型態呢
直覺得˙會把它看成 int* 型態但其實他們是
等價於 int* i; int j
這時候我會建議你都把他們放後面吧
int *i, *j; or int *i ,j;
這樣就更容易閱讀了

副程式

為何副程式必須導入指標

有了前者得概念,現在來出一到小題
如何使用副程式修改變數
簡單的來形容主程式內有一個變數
我要呼叫一個副程式修改i的數值
int i=0;
modify();
如何實做呢 https://goo.gl/2EMGo3

副程式引入處指標與陣列不同

fun(int* arr);

fun(int arr[4]);
用途上來看最主要大概差異在
前者沒有把數字定死,想傳幾個都可以傳
即便是後者,你傳入一個長度是5的陣列能然能取到
第5個的數值,這純粹只是運氣好,第5個的數值
只是因為宣告時記憶體是連續的,運氣好可以讀到
程式如果複雜了,並不能保證他不會修改

如何從副程式得到指標長度

通常來說都會在下標的第[0]個儲存長度
這可以節省運算時間,也讓你更好操作
C++可以透過樣板取得取得長度
template<size_t N>
void arr_len(int (&arr)[N]) {
    std::cout << "sizeof = " << sizeof(arr) << " / ";        
    std::cout << sizeof(arr[0]) << std::endl;
    std::cout << "len = arr[" << N << "]" << std::endl;
}
樣板會干擾到拆分程式,還是建議採用前者

間接定址與直接定址

假設有一個二微陣列是 [2][2]
那麼在記憶體上第三個是 [1][0]
輸入 [1][0] 在操作上必須找兩次,
先找到[0]的地址再去查找地址的數值
速度上會略低,如果宣告成一微陣列
自己手動算出[2][2]是第3個
效率上會來的好一些,在操作上也較容易

為何需要指標的指標

  1. 存取動態二維陣列
  2. 副程式拆解上的需求
這可能有點難形容,兩者其實
也差不都在形容同一件事情
直接看代碼或許會比較好理解
核心代碼
imch imgraw::cubicInterpolate (imch* p, double x) {
    double temp = (double)(p[1] + 0.5 * 
        x*(p[2] - p[0] +x*(2.0*p[0] - 5.0*p[1] + 4.0*p[2] - 
            p[3] + x*(3.0*(p[1] - p[2]) + p[3] - p[0]))));
    return (imch)temp;
}
用來控制核心代碼的驅動
imch imgraw::bicubicInterpolate (imch** p, double y, double x) {
    imch* arr = new imch[4];
    for (int i = 0; i < 4; ++i)
        arr[i] = cubicInterpolate(p[i], x);
    return cubicInterpolate(arr, y);
}
如果沒有將核心代碼拆分出來,核心代碼必須重複5次

指標的指標

動態二維陣列的應用
// 創建
int** ptr = new int* [2];
for (int i = 0; i < 2; ++i)
    ptr[i] = new int [2];

// 釋放
for (int i = 0; i < 2; ++i)
    delete [] ptr[i];
delete [] ptr;

結構指標

結構
struct node{
    int i;
};
結構指標要用->去指向
node a, *b;
b = &a;
a.i = 1;
cout << b->i << endl;
return 0;

虛無指標

這應該很少會用到,但如果你要把程式寫好
寫得足夠嚴謹,就必須得用他,
很多底層的代碼,都是這樣定義的
//接收不同型態的資料
void pri_int(void* data){
    int temp=(int)*data;
    cout << "temp=" << temp << endl;
}
這個副程式將可接受各種型態的指標
最終cast成整數的樣貌,印出

2016年8月27日 星期六

自訂 Youtube 播放速度 大於 > 2 倍數

內建的播放速度只有到2而已,其實可以自由調整至更快的
  1. 瀏覽器中按下 F12 打開 "開發者工具視窗"
  2. 切換到 "主控台(Console)" 這個分頁
  3. 輸入下方的代碼 (這邊以5倍數為範例),並按下Enter執行
document.getElementsByTagName("video")[0].playbackRate = 5


2023-07-17

截止至目前還有效,大概就這麼個順序操作可以任意調整倍率。



2016-8-27

最後面的 5 是播放倍數,可以自由設定

2016年8月25日 星期四

Win7 8 10 如何設定 資料夾內 所有子資料夾 變成超大圖示 [批次更改圖示顯示方式]

請注意不要漏掉任何步驟了,改了整個Windwos都會變了
可別整台變成你不想要的形式了,到時候一定很乾XDD
有的時候你可能想要修改整個資料夾,包含資夾內的子資料夾
一口氣全部修改成超大圖示,卻不曉得該怎麼辦
搜了一下網路,其實沒什麼資料 (我大概是一年前蒐的)
只好一個一個資料夾慢慢改QQ
改成大圖示還好,有預設值可以套用,超大圖示就沒了
這裡會介紹如何詳細的批次修改系統內的顯示方式
主要兩個概念
  • 套用預設規則
  • 更改系統預設規則

套用預設規則

先說說如何批次套用預設的規則
這樣就會全部都變成大圖示摟,如打打勾套用到子資料夾
裡面有包含的資料夾通通都會變成大圖示了

更改系統預設規則

首先非常重要的一點
注意請關掉所有資料夾留一個就好
開啟你的使用者文件(或貼上我提供的位置)
%USERPROFILE% \Pictures
將該位置改成大圖示,並更動預設檢視數值
之後再執行上一步 套用預設規則
套用成圖片的預設規則(剛剛改的)
就會發現全部都變成超大圖示了
改好之後可以直接從上面修改成大圖示
或是詳細清單的方式,增加最外層資料夾
一次可瀏覽的項目,不會影響子資料夾
為什麼要反過來寫是先讓你熟悉一下
而且多數可能只會用到上一步XDD

細節

  1. 套用時會針對當前顯示最上層的資料夾套用規則
    所以才跟你說要關乾淨XD
    如果你有一個是普通型態的資料夾

    (幾乎所有的資料夾都會是一般項目
    除非你放了一堆影片進去,他自動轉態成影片)
    這時候如果你為了方便將一般項目改成大圖示
    沒選好你這一套用,可能整個C曹都變成大圖示了
  2. 套用規則只能有5個

    也就只有這麼5個能用而已啦XD
    沒辦法自己在多設定了
    我個人是把圖片改成超大圖示
    這樣比較不會干擾到其他地方

嗯…這一篇其實是用來高效率挑 (( 誤
試著在D槽的右上角輸入底下字串試試看
((*cari* OR *1pon*) AND *.mp4) OR (~<n??? OR ~<n????) AND (*.mp4 OR *.wmv)
這種搜索方式非常實用,對於把電腦當圖書館的人來說
看看你的電腦都搜出了些什麼XD
自己在替換成適合的相關字符
一樣用 OR (你的規則) 就可以了
注意 OR 是大寫且前後都要有空格
最後再改成適當的方式顯示
這裡的顯示方式會儲存,記得改回來相關性
不然真要找檔案的時候,會不太好找XDD