2017年6月23日 星期五

筆電安裝 SSD (M2) 之後如何選擇以 SSD (M2)開機

筆電安裝 SSD (M2) 之後如何選擇以 SSD (M2)開機

記得新硬碟預設都是MBR要改成GUID才可以正常使用,改變的方式直接在windows內修改即可。
另外請不要做4K對齊,大多數的網站都說要但那其實沒必要,只要使用windwos的光碟或USB把分割區砍光在重新切割(會切好幾份正常的)就已經對齊;真正需要對齊的是XP,XP的安裝光碟不會幫你對齊,必須手動執行對齊。
還有一堆優化SSD的手續呀~千萬不要,現在都2017了~請相信微軟是一家有能力的公司,放心交給他都已經幫你做好了。不過如果你是在XP還是有必要要自己做。

選擇硬碟

如果不想移除舊系統可以留著,有個兩個方式可以選擇使用M2開機,一種是硬碟拆了只留SSD它會自動幫你選到SSD開機,在接上原本的硬碟。
如果需要臨時開到別的硬碟,去BIOS開啟F12選單,可以選硬碟
另一種是你不能拆,然後又偏偏他是開你的HDD那你只好自己建立開機選單了,建立方式也不難,進去BIOS先設定密碼(這是必要的才能啟用功能),然後再設定密碼那裏就有一個瀏覽EFI開機檔,檔案並不多你就瀏覽一下很容易可以找到的,忘了拍照。

使用MBR硬碟

很多網站建議應該使用MBR,千萬不要這會造成不少後果…
已知可能造成關機會黑屏然後電源沒切,解決方式是去電源關閉快速啟動。這個舉動會大大減緩開機速度,沒辦法使用混合開機。
已經裝了沒事就好了,開機慢一點還是可以用。

2017年6月21日 星期三

OpenCV 3.2.0 vc14 如何安裝在 Visual Studio 2017

OpenCV 3.2.0 vc14 如何安裝在 Visual Studio 2017

先到官方下載這兩項軟體 (點擊有連結)
OpenCV 為了避免不必要麻煩與最佳化
建議直接解壓縮到C槽不要增加自己的難度了。


文件說明

build文件是官方已經幫你預先編譯好的檔案,開進去opencv\build\x64,可以看到vc14的字樣,vc14好像是 Visual Studio 內的版本 2017 就是 cv14,你可以在軟件內發現不過我忘記從哪裡看了。
也可以從路徑內看另一篇文章 如何在 Visual Studio 2017 使用 bits/stdc++.h 裡面的路徑就有這個代號了。如果是你是舊版本的vc翻翻看路徑是寫版本多少,只要是14都能用。
其他還有像是python就抓python的資料夾那個檔案就可以用在python上了 python 站內文章;如果是MinGW官方沒有幫你預先編譯好,要自己從source這個用cMake自己編譯MingGW站內文章
總而言之會用到的只有
  • build/include
  • build/x64/vc14


部屬 OpenCV

提醒~如果你什麼都不知道最好直接把opencv解壓縮到C槽,降低難易度
首先只要做一次就好的是
  • 系統環境變數加入 bin 路徑
編譯器大概需要三個步驟(每次第一次開新專案)
  • 編譯器加入 include 路徑
  • 編譯器加入 lib 路徑
  • 編譯器加入 lib 檔案
另外 debug/release 以及 x86/x64 都要個別設定,開一次專案要設定4次

環境變數(說明文字在圖下)


搜索一下你的電腦環境變數或系統內容都可以(也可以直接對著本機按右鍵內容)

這裡就有環境變數給你設定了

增加一下include
到這裡就可以了,只剩下VC的部分

設定編譯器

懶人包打開就能用了:OpenCV_Test
這裡每次開新專案都要重新設定一次,設定儲存在專案上而不是總體設定



開一份新的空專案


新增一份code
/**********************************************************
Name :
Date : 2016/05/29
By   : CharlotteHonG
Final: 2016/05/29
**********************************************************/
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;

int main(int argc, char const *argv[]) {
    /* 畫布 */
    Mat img(270, 720, CV_8UC3, Scalar(56, 50, 38));
    /* 直線 */
    line(img, Point(20, 40), Point(120, 140), Scalar(255, 0, 0), 3);
    /* 實心方塊 */
    rectangle(img, Point(150, 40), Point(250, 140), Scalar(0, 0, 255), -1);
    /* 實心圓 */
    circle(img, Point(330, 90), 50, Scalar(0, 255, 0), -1);
    /* 空心橢圓 */
    ellipse(img, Point(460, 90), Size(60, 40), 45, 0, 360, Scalar(255, 255, 0), 2);
    /* 不規則圖形 */
    Point points[1][5];
    int x = 40, y = 540;
    points[0][0] = Point(0 + y, 50 + x);
    points[0][1] = Point(40 + y, 0 + x);
    points[0][2] = Point(110 + y, 35 + x);
    points[0][3] = Point(74 + y, 76 + x);
    points[0][4] = Point(28 + y, 96 + x);
    const Point* ppt[1] = { points[0] };
    int npt[] = { 5 };
    polylines(img, ppt, npt, 1, 1, Scalar(0, 255, 255), 3);
    /* 繪出文字 */
    putText(img, "Test Passed !!", Point(10, 230), 0, 3, Scalar(255, 170, 130), 3);
    /* 開啟畫布 */
    imshow("OpenCV Test By:Charlotte.HonG", img);
    waitKey(0);
    return 0;
}
貼上測試代碼

先改成x64

對著專案點右鍵屬性

設定include路徑

設定lib路徑


加入lib檔案(debug模式選有d結尾的)
如果你要改成 release 模式記得前面的路徑還要再設定一次
  • 編譯器加入 include 路徑
  • 編譯器加入 lib 路徑
  • 編譯器加入 lib 檔案

運行

設定好之後直接按F5運行吧

C++ Raw 轉檔 BMP 互轉 實作範例 (BMP格式檔頭解析)

C++ Raw 轉檔 BMP 互轉 實作範例 (BMP格式檔頭解析)

BMP圖檔大致分為四個部分
  • 檔案檔頭(14byte)
  • 圖片檔頭(40byte)
  • 調色盤(1024byte)
  • Raw檔
這裡的byte看成是一個字元(char),如果是字元與Raw檔讀取就順著讀而已,比較特別是數字讀取的時候要一起讀;比如說根據表頭某4byte是一組的他們是 00 FF 00 00 那你要反著讀變成 0000FF00 -> FF00 而不是直接讀取。

檔案檔頭(14byte)

範例代碼:(占用位元可以從代碼上看到)
struct FileHeader {
    unsigned char type[2]= {'B', 'M'};
    byte4_t size;
    byte2_t reserved1=0;
    byte2_t reserved2=0;
    byte4_t headSize=54;
};
其中有寫數值的地方是類內初始化(C++11標準才可以使用),有寫的地方代表幾乎就那樣了,通常不會動到,只要補空白的地方就好。
第一個比較特別的是他是BM,我用這樣的型別代碼比較容易辨識,使用 byte2_t 就沒辦法辨識了會寫成 type=0x424D
再來size是只檔案大小,就是包含上述全部資料大小,這也會是你直接對BMP右鍵內容看到的容量大小。
再來最後面的54是固定的就是14+40,不過如果你是用灰階圖記得要加上1024(調色盤占用的)。

圖片檔頭(40byte)

範例代碼:(占用位元可以從代碼上看到)
struct InfoHeader {
    byte4_t size=40;
    byte4_t width;
    byte4_t height;
    byte2_t planes=1;
    byte2_t bits;
    byte4_t compression=0;
    byte4_t imagesize;
    // 72dpi=2835, 96dpi=3780, 120dpi=4724, 300dpi=11811
    byte4_t xresolution=0;
    byte4_t yresolution=0;
    byte4_t ncolours=0;
    byte4_t importantcolours=0;
};
size檔頭的大小
height width 圖片的長與寬
bits 位元數,彩圖要設RGB 8*3=24,灰階圖設8
imagesize 指的是 長*寬,如果是彩圖有RGB還要再 *3
ncolours 指的是調色盤的顏色數,彩圖RGB因為不用自己寫調色盤用系統的所以設0,灰階圖擇要自訂調色盤這裡要設256
resolution 指的是密度,一般軟體好像也不看都是設0,windwos電腦預設是96dpi,大概就差別在你把這張圖拉上PPT上設越高會縮的越小。

調色盤(1024byte)

這個是可選的,如果圖片來源是 RGB 24bit 的圖就可以留空不管他,如過圖片是灰階圖你就要自己補上調色盤,調色盤意思其實也很簡單就是 00 00 00 00~ FF FF FF 00 而已,這是因為灰階圖只需用一個byte表示,但是整張BMP需要用 RGB 表示,所以調色盤的功用就是把看到的RAW檔,就比如看到 00 變成 00 00 00 看到 FF 變成 FF FF FF
你可以一次做好整份調色盤在寫入,也可以用for迴圈寫入,數量不多不會太損效能可以用for比較整潔些,大致如下寫法。
for(unsigned i = 0; i < 256; ++i)
    img << uch(i) << uch(i) << uch(i) << uch(0);

Raw檔

比較特別的是讀取的方式是從圖的左下角開始往右邊上面讀取,而且數據是BGR反過來的,並且他們的行會對齊4byte,如果圖片是40x42那麼你寫入的時候要寫成40x44不足的2位元補空白0。
算對齊的代碼如下
size_t alig = (4 - info_h.width%4)%4;
算出來是2的話就是說每行的結尾要塞 2 個 char(0) 就是 0x0000
算出來是4的話就是說每行的結尾要塞 4 個 char(0) 就是 0x00000000

注意

灰階圖要多寫調色盤,有三個地方要更動
FileHeader 的 size        +1024
FileHeader 的 headSize    +1024
InfoHeader 的 size        +1024
InfoHeader 的 ncolours    =256
除此之外也記得讀檔的時候檔案指標要跳過調色盤(建議是直接抓headSize比較省事)。

範例

int main(int argc, char const *argv[]) {
    vector<unsigned char> raw_pix;
    string rawName = "Seymour_Park_960x540_24bit.raw";
    Raw::read_raw(raw_pix, rawName);
    string bmpName = "Seymour_Park.bmp";

    // 存彩圖
    Raw::raw2bmp(bmpName, raw_pix, 960, 540);
    system(bmpName.c_str());
    // 存灰階
    Raw::raw2gray(raw_pix);
    Raw::raw2bmp(bmpName, raw_pix, 960, 540, 8);
    system(bmpName.c_str());

    // 讀取 Bmp
    vector<unsigned char> raw_pix2;
    Raw::read_bmp(raw_pix2, bmpName);
    Raw::write_raw("test_960x540_24bit.raw", raw_pix2);
    system("test_960x540_24bit.raw");
    return 0;
}
主要技巧是利用 struct 與 unio 混合可以做位元的寫入
再利用重載 operator << 把位元一個一個推入檔案內

2017年6月15日 星期四

什麼時候必須要用到指標

什麼時候必須要用到指標

很多時候會遇到必須使用指針的情況,舉例來說以下兩個降低依存關係的技巧,才不用動一個一個地方整份專案重編。
  • Handle Class
  • Protocol Class
實際上應該還有很多場合不得不用,或使用會更好。
舉個簡單的例子,考慮一個互相依存的類別,雙方彼此都要有雙方
struct A{
    B b;
};
struct B{
    A a;
};
這時候你怎麼辦呢在類別A內找不到B的定義沒但法實作
舉兩個簡單手段避開依存關係
  • vector (或一個設計良好自訂的容器)
  • 指針
struct B; // 前置宣告
struct A{
    B* b;
};
struct B{
    A a;
};
struct B; // 前置宣告
struct A{
    vector<B> b;
};
struct B{
    A a;
};
其中的前置宣告,也可以使用詳細的型別說明符(Elaborated type specifier)取代
struct A{
    struct B* b;
};

2017年6月8日 星期四

為什麼 cin.get() getline() 沒辦法讀取第二個

為什麼 cin.get() getline() 沒辦法讀取第二個

主要是偵測到結束符號導致被略過,最簡單的方式直接使用
string str;
cin >> str;
就可以連續讀取了
如果真的要用標題的方式則要讓串流做完這一次、調整指針、清除才可以
提供以下幾個方法,是用在不同的情況,需要使用再去詳細爬文
cin.ignore();
cin.sync();
cin.seekg(1,ios::end);
fflush(stdin);

2017年6月5日 星期一

指針(point) 與 參考(ref) 有什麼不同之處

指針(point) 與 參考(ref) 有什麼不同之處

tags: C++ Concept2
本文所指的指針的指針指的是指標,個人覺得這樣比較好做區別
初學時時常讓人搞不清楚的兩個不同的東西,這邊提供幾個大原則做判斷
指針:可以儲存記憶體位置的型別
參考:就好像別名一樣可以完全等同於所指之物
比較特別的還有一種情況叫做(*\&)指針的參考,這又是什麼呢?

兩個符號的用法

分別是
  • *取址 reference
  • &取值 dereference
他們放在非宣告時的變數的前方,從英文可以看出他們具有相反的關係。
首先最讓人搞不清楚的是為什麼他們在宣告時有不同的關係,那根本就是不一樣意思了。
int* i;
int& a;
你把它當作別的東西來看直接把整串看做是一個型別。
我的意思是你不要這樣看int* i; 而直接是 int* i;
前者表示宣告一個指針容器,後者表示宣告一個別名,跟剛剛的*&完全是兩回事。
由此我也更推薦你使用 int* i; 而不是 int *i;這樣更容易表達。
除非你需要連續宣告,這就真的不得已了int *i, *j; 連續宣告時要個別指定。
回到剛剛的取址與取值簡單來說就是你現在有一個變數,它存在記憶體的某個地方,這個某個地方會用一串數值表示位置比如說 0x01
現在你手上拿到 p=0x01 你希望獲取他的數值就是使用取值 *p 獲取內容
你現在手上拿到 p=0; 你希望獲取他的地址就是使用取址 &p 獲取地址

地址的傳遞可以共同編輯

函式(包含main)內都有各自的空間,彼此是不同互相存取的除非你使用全域函式。
他就像一個公用櫃子一樣,只要你告訴別人我的東西放在幾號櫃子別人就可以來存取。
比如以下的代碼
int i=0;
int* p=&i;
現在p也可以修改i
*p = 1;
把它放到函式內就像這樣
void fun(int* p){
    *p = 1;
}
使用時就像這樣
fun(&i);

參考基本用法

底層裡面都是做指針的存取,使用方法怎麼區別可以這樣想像
參考就像一個不用輸入符號的指針
什麼意思呢,假設有一個指針為下
int i=0;
int* p=&i;
現在p也可以修改i
如果寫成參考就像這樣子
int i=0;
int& ali=i;
現在ali也可以修改i,現在操作ali就像在操作i
叫王小明的綽號 阿明 就像在叫王小明一樣。
放到函式可以省很多事情
void fun(int& p){
    p = 1;
}
使用時就像這樣
int i=0;
fun(i);
現在你在函式內的操作以及呼叫函式時的操作,全部都不用加上符號上了,是不是更好用呢?
或許你會在學到參考後一股腦地全部換參考,但其實他們之間大概有細微的差異

指針

  • 需要檢查有效性
  • 可以指向Null表示無效,也可以隨時更換指向的目標
  • 有指針的指針

參考

  • 不需檢查有效永遠有效
  • 不能換參考,且只能在宣告時給定目標
  • 沒有參考的參考
彙整出來的兩條守則:
  1. 不想付出檢查成本就用參考
  2. 需要更動指向的目標物或初始化為無效,只能用指針

活用參考與指針

很多時候他們是可以互相通用的,這可能不好記憶,透過練習題更容易熟悉,詳見以下的範例
有一個函式
  • 可以在函式內改他的值
  • 並使回傳的可以更改內容
看起來有些繞口,直接看代碼會比較好理解
要可以做到以下的樣板功能
int i;
fun(/*i*/);       //更改 i 的值
fun(/*i*/) += 10; //並加10
大致可以有以下四種做法,各字看一次,做一次應該10分鐘就可以入門參考與指針了
#include <iostream>
using namespace std;

int* fun1(int* i){
    *i = 1;
    return i;
}
int* fun2(int& i){
    i = 2;
    return &i;
}
int& fun3(int* i){
    *i = 3;
    return *i;
}
int& fun4(int& i){
    i = 4;
    return i;
}

int main() {
    int i=0;
    *fun1(&i) += 10;
    cout << "i=" << i << endl;
    *fun2(i) += 10;
    cout << "i=" << i << endl;
    fun3(&i) += 10;
    cout << "i=" << i << endl;
    fun4(i) += 10;
    cout << "i=" << i << endl;
    return 0;
}