2017年7月20日 星期四

CMD 批次檔 環境變數 長度太長 無法新增

CMD 批次檔 環境變數太長超過 1024 怎麼辦

換個工具吧QuQ,這個真的很惱人。不過還好這個工具從Win7開始就有了不用太擔心支援性。
除非長度限制之外還有一個很討人厭的是,我一直找不到可查看使用者變數的方法,終於讓我找到了,這個指令可以查看使用者的環境變數!
你可以透過cmd 輸入 powershell 啟動,如果不想離開 cmd 就在命令前加上 powershell。比如新命令 Get-Command 則輸入 powershell Get-Command。然後有 " 前要加斜線。
powershell的批次檔結尾是.ps1

環境變數設置與查看

這兩個函式可以用來區別使用者變數與系統變數
你也可以簡化他們為”User”, “Machine”,稍後會看到。

查看環境變數

[environment]::GetEnvironmentVariable("PATH", "User")
[environment]::GetEnvironmentVariable("PATH", "Machine")
還有一個比較簡單的方法
$env:path

設置環境變數

警告,記得先儲存自己的環境變數!儲存方法如下,幫你存到桌面。
cd ~;[environment]::GetEnvironmentVariable("PATH", "User") > Desktop/PATH_User.txt
cd ~;[environment]::GetEnvironmentVariable("PATH", "Machine") > Desktop/PATH_Machine.txt
設置環境變數
[System.Environment]::SetEnvironmentVariable("PATH", $Env:Path + ";C:bin", "User")
[System.Environment]::SetEnvironmentVariable("PATH", $Env:Path + ";C:bin", "Machine")
這個黑科技可以擺脫2048限制了,不過環境變數還是有總長度限制,能省則省。
還有一點就是,他終於有防呆了!不會新增重複的,自動避免新增一樣的環境變數。


cmd批次檔寫法如下

@Echo Off
Title AddPath - By:Charlotte.HonG
:: Date :2016/05/28
:: Final :2017/07/20

::===========================================================
::確認是否為管理員權限
call :IsAdmin
set appPATH=%~dp0bin
powershell [System.Environment]::SetEnvironmentVariable(\"PATH\", $Env:Path + \";%appPATH%;\", \"Machine\")
::===========================================================
Exit

:IsAdmin
@Echo Off
Reg.exe query "HKU\S-1-5-19\Environment"
If Not %ERRORLEVEL% EQU 0 (
  Cls
  Echo [權限不足] 需使用管理員權限開啟
  Pause & Exit
)
goto:eof


參考

使用 cmd or powershell 列出當前目錄檔案或特定副檔名

使用 cmd or powershell 列出當前目錄檔案或特定副檔名

這裡提供cmd與powershell兩個方法,另外如果要在cmd下執行powershell命令在最前方加入powershell指令即可。
須注意日文檔名的儲存的txt檔案,程序要讀檔會比較麻煩,能不用就不要用比較好。

CMD

列出當前檔案
dir "*.lib"
輸出到文件
dir "*.lib" /b /on > "Lib_Lists.txt"
日文檔名使用 cmd /u /c dir /b /on >list.txt
移動文件
MOVE %FILENAME% %LISTPATH%

批次檔

獲得 指定目錄 lib資料夾內的所有 .lib 檔案清單,並儲存到 批次檔所在目錄
::@Echo Off
Title CreatList - By:Charlotte.HonG

set FILENAME="Lib_Lists.txt"
set FILEPATH="lib"
set LISTPATH=%~dp0

cd %FILEPATH%
dir *.lib /b /on > %FILENAME%
MOVE %FILENAME% %LISTPATH%


powershell

$file=Get-ChildItem -Recurse -include "*.lib"
set-content $file.name -path Lib_List.txt
日文檔名則在第二行結尾增加 -Encoding Unicode

2017年7月10日 星期一

C++ 高斯模糊 詳細解析與源代碼

C++ 高斯模糊 詳細解析與源代碼

圖片上的高斯模糊有種兩方式,一種是二維的遮罩一種是一維的,不過就算是一維的X方向做一次Y方向再做一次也是可以相等於二維的。
一維相對來說比較好做、比較好講,也可以稍微避免邊界的問題,這裡主題就已一維為主。
步驟
  • 利用公式得出高斯矩陣
  • 利用高斯矩陣做捲積

公式

參考一下維基百科的公式:維基百科高斯模糊
這個公式有兩個變數是可以決定的,r 與 sigma(那個圈圈)
// 高斯公式
float GauBlur::gau_meth(size_t r, float p) {
    float two = 2;
    float num = exp(-pow(r, two) / (two*pow(p, two)));
    num /= sqrt(two*M_PI)*p;
    return num;
}
sigma越大會越模糊,r 是指矩陣位置
在實際產生之前還要決定矩陣要設多大,這可以自己設定也可以用公式算
// 計算矩陣長度
int mat_len = ((p-0.8) / 0.3+1.0) * 2.0;
比如說我設定成 sigma=1.6 那麼算出來需要長度為 7 的矩陣,當然你也可以自己決定要幾個,越多也會越模糊。

高斯矩陣

決定好矩陣長度之後你就可以利用公式算出來了
公式 r = 3 2 1 0 1 2 3
高斯矩陣 0 1 2 3 4 5 6
如此得到高斯矩陣。
得出之後還要把他們規一化,7個加起來總和是1
作法很簡單,讓矩陣個別除以他們的總和就可以了
寫成代碼像這個樣子
// 高斯矩陣
vector<float> GauBlur::gau_matrix(float p){
    vector<float> gau_mat;
    // 計算矩陣長度
    int mat_len = ((p-0.8) / 0.3+1.0) * 2.0;
    if (mat_len % 2 == 0) {++mat_len;}
    // 一維高斯矩陣
    gau_mat.resize(mat_len);
    float sum=0;
    for(int i=0, j=mat_len/2; j < mat_len; ++i, ++j) {
        float temp;
        if(i) {
            temp = gau_meth(i, p);
            gau_mat[j] = temp;
            gau_mat[mat_len-j-1] = temp;
            sum += temp += temp;
        } else {
            gau_mat[j]=gau_meth(i, p);
            sum += gau_mat[j];
        }
    }
    // 歸一化
    for(auto&& i : gau_mat) { i /= sum; }
    return gau_mat;
}
到這裡為止算出來的矩陣是
0 = 0.0441465
1 = 0.117223
2 = 0.210611
3 = 0.256038
4 = 0.210611
5 = 0.117223
6 = 0.0441465
你也可以直接抄這個矩陣,直接拿去用

捲積

這裡需要引入一個名詞遮罩
假如說現在有9宮格,鍵盤上的,我的遮罩大小是 1x3 橫的,位置是5,那麼遮罩的矩陣是
4 5 6
依此類推,現在你讀入一張圖,剛剛的高斯矩陣長度多少遮罩就多少,需要你罩住長度的7的矩陣,位置從0跑到最後。
假如罩到邊邊,那麼缺的地方可以補邊緣或是鏡像另一邊開始算回來,都可以有很多方式,一般最簡單的建議補邊邊就好。
一樣是剛剛的例子舉例假如我選中鍵盤9宮格 7 那麼遮罩的矩陣是
7 7 8
依此類推。
罩住之後就可以開始做捲積了,記得不要再同一個陣列做要寫到另一個陣列不然會被影響。然後加總的數值型態要是float或double不然出來圖會偏黑。
double sum = mask[0] gau[0] + mask[1] gau[1]…;
把它們各相乘最後再相加寫到新的陣列就可以完成了。

源代碼

// 高斯模糊
class GauBlur{
public:
    static void raw2GauBlur(vector<unsigned char>& img_gau,
        vector<unsigned char>& img_ori,
        size_t width, size_t height, float p);
private:
    static vector<float> gau_matrix(float p);
    static float gau_meth(size_t r, float p);
};
// 高斯模糊
void GauBlur::raw2GauBlur(vector<unsigned char>& img_gau,
    vector<unsigned char>& img_ori,
    size_t width, size_t height, float p)
{
    // 設定正確的大小
    img_gau.resize(img_ori.size());
    // 緩存
    vector<double> img_gauX(img_ori.size());
    // 高斯矩陣與半徑
    vector<float> gau_mat = gau_matrix(p);
    const int r = gau_mat.size()/2;
    // 高斯模糊 X 軸
    const size_t r = gau_mat.size() / 2;
    for (unsigned j = 0; j < height; ++j) {
        for (unsigned i = 0; i < width; ++i) {
            double sum = 0;
            for (unsigned k = 0; k < gau_mat.size(); ++k) {
                int idx = i-r + k;
                // idx超出邊緣處理
                if (idx < 0) {
                  idx = 0;
                } else if (idx >(int)(width-1)) {
                  idx = (width-1);
                }
                sum += img_ori[j*width + idx] * gau_mat[k];
            }
            img_gauX[j*width + i] = sum;
        }
    }
    // 高斯模糊 Y 軸
    for (unsigned j = 0; j < height; ++j) {
        for (unsigned i = 0; i < width; ++i) {
            double sum = 0;
            for (unsigned k = 0; k < gau_mat.size(); ++k) {
                int idx = j-r + k;
                // idx超出邊緣處理
                if (idx < 0) {
                  idx = 0;
                } else if (idx > (int)(height-1)) {
                  idx = (height-1);
                }
                sum += img_gauX[idx*width + i] * gau_mat[k];
            }
            img_gau[j*width + i] = sum;
        }
    }
}
// 高斯公式
float GauBlur::gau_meth(size_t r, float p) {
    float two = 2;
    float num = exp(-pow(r, two) / (two*pow(p, two)));
    num /= sqrt(two*M_PI)*p;
    return num;
}
// 高斯矩陣
vector<float> GauBlur::gau_matrix(float p){
    vector<float> gau_mat;
    // 計算矩陣長度
    int mat_len = ((p-0.8) / 0.3+1.0) * 2.0;
    if (mat_len % 2 == 0) {++mat_len;}
    // 一維高斯矩陣
    gau_mat.resize(mat_len);
    float sum=0;
    for(int i=0, j=mat_len/2; j < mat_len; ++i, ++j) {
        float temp;
        if(i) {
            temp = gau_meth(i, p);
            gau_mat[j] = temp;
            gau_mat[mat_len-j-1] = temp;
            sum += temp += temp;
        } else {
            gau_mat[j]=gau_meth(i, p);
            sum += gau_mat[j];
        }
    }
    // 歸一化
    for(auto&& i : gau_mat) { i /= sum; }
    return gau_mat;
}
使用方式如下(須自己讀入一張灰階圖到 raw_img 陣列內)
vector<unsigned char> gau_img;
GauBlur::raw2GauBlur(gau_img, raw_img, height, width, p);

2017年7月7日 星期五

[ C / C++] 讀取任意目錄的 檔案名稱、路徑、濾特定副檔名

[ C / C++] 讀取任意目錄的 檔案名稱、路徑、濾特定副檔名

存取任意位置的目錄 - 第一版

這個可以讀取任意目錄位置下的所有檔案與目錄

  • 第一版是不能讀子目錄的,需要讀子目錄請繼續往下看
  • 如果需要過濾特定檔案,比如說圖片 *.jpg *.bmp 之類的
    改一下 extenName 擴展名的部分 *.jpg 就可以了
/*****************************************************************
Name : ReadFiles path
Date : 2017/05/22
By   : CharlotteHonG
Final: 2018/03/08
*****************************************************************/

#include <stdio.h>
#include <string.h>
#include <io.h>
#include <direct.h>

void getDirFile(const char* definePath, const char* extenName){
    char buff[1024];
    _chdir(definePath);
    unsigned long long hFile;
    struct _finddata_t fileName;
    hFile = _findfirst(extenName, &fileName);
    do {
        sprintf(buff, "%sprintf\\%s", definePath, fileName.name);
        printf("%s\n", buff);
    } while(hFile != -1 && _findnext(hFile, &fileName)==0);
}

int main(int argc, char const *argv[]){
    // 設置目錄與檔案類型
    const char* definePath = "C:\\";
    const char* extenName = "*.*";
    // 獲取目錄
    getDirFile(definePath, extenName);
    return 0;
}

第二版

原本第一版是不能讀取子目錄的,寫好第二版可以正常讀取了。

/*****************************************************************
Name : ReadFiles path
Date : 2017/05/22
By   : CharlotteHonG
Final: 2021/04/20
*****************************************************************/
#include <stdio.h>
#include <string.h>
#include <io.h>

void getFileList(const char* _dirPath, const char* extenName){
    struct _finddata_t file;
    intptr_t hFile;
    // 修正路徑
    char dirPath[256] = {0};
    if (_dirPath[strlen(_dirPath)-1]!='\\')
        sprintf(dirPath, "%s\\", _dirPath);
    else
        sprintf(dirPath, "%s", _dirPath);
    // 檢查路徑是否有效
    char buff[256] = {0};
    sprintf(buff, "%s%s", dirPath, extenName);
    if ((hFile = _findfirst(buff, &file)) == -1)
        perror("path error"), exit(1);
    int i=0;
    // 開始搜索
    do {
        // 避開當前目錄[.]和上一層目錄[..]
        if (!(strcmp(file.name, ".")) || !(strcmp(file.name, "..")))
            continue;
        // 子目錄
        if (file.attrib == _A_SUBDIR) {
            sprintf(buff, "%s%s", dirPath, file.name);
            getFileList(buff, extenName);
            // 檔案
        } else {
            sprintf(buff, "%s%s", dirPath, file.name);
            printf("%s\n", buff);
        }
    } while (_findnext(hFile, &file)==0);
}

int main(int argc, char const* argv[]) {
    const char* dirPath="Z:\\a";
    const char* extenName="*.*";
    getFileList(dirPath, extenName);
    return 0;
}

如果需要把檔名封裝到物件上,可以參考這一份檔案,是純C寫的。
https://gist.github.com/hunandy14/24a5e7690a18e6d3cf320e68d8ccc7fd




簡易的存取 main.c 當下的目錄文件

第二種方式是透過系統本身的命令列 dir 來讀取。

關於這個解決方案有更好的版本寫在這篇站內文
https://charlottehong.blogspot.com/2021/04/c-c.html

C++

/*****************************************************************
Name : ReadFiles path
Date : 2017/05/22
By   : CharlotteHonG
Final: 2017/05/24
*****************************************************************/
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char const *argv[]){
    system("dir /b /on >list.txt");
    fstream f("list.txt", ios::in);
    for(string s;f >> s;) {
        cout << s << endl;
    }
    return 0;
}

C語言

/*****************************************************************
Name : ReadFiles path
Date : 2017/05/22
By   : CharlotteHonG
Final: 2017/05/24
****************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char const *argv[]){
    system("dir /b /on > list.txt");
    FILE *pFile = fopen("list.txt","r");
    for(char buf[128]; fgets(buf, 128, pFile) != NULL;){
        if(buf[strlen(buf)-1]='\n')
            buf[strlen(buf)-1] = '\0';
        printf("%s\n", buf);
    }
    return 0;
}

2017年7月5日 星期三

O Bike 騎乘體驗與收費說明 大學生無信用卡也可以

O Bike 騎乘體驗與開通教學 大學生無信用卡也可以

圖片擷取自官方網站

註冊帳戶

註冊優惠連結:https://goo.gl/FZWb6H
點擊後輸入手機即可以完成註冊會員
記得輸入的時候手機號碼要去掉首號的 0

下載APP

官方連結:https://www.o.bike/tw/download.html
下載後登入帳戶即可使用
第一次登入時需綁定信用卡並支付 $900 訂金,這個訂金是可以退回的,並且在限定次數內是不會扣手續費的,你可以拿到完整的 $900。
可以使用郵局簽帳卡須開通非過卡交易與國外交易,支付是屬於國外支付。
如果你還是學生沒有信用卡可以使用,可以去開通郵局的辦一張金融卡,記得開通上述功能,或買個讀卡機線上開通。
這個可能比較簡單快速,帶著存摺印章去辦就好了
或者這裡介紹一家可以很快拿到簽帳金融卡的銀行
王道銀行:官方連結
註冊過程需要拍身分證與健保卡,可以使用手機拍攝。過程很簡單,不含假日註冊完畢我那時候大概3天就拿到簽帳卡了。
除此之外需要跑一趟戶政事務所,辦理自然人憑證,這手續很快大概5分鐘就搞定了。
以及需要購買一台讀卡機,之後開卡會用到。
拿到簽帳卡之後就是一張可以線上刷卡的金融卡了,第一次使用須從APP開通
王道銀行APP:https://goo.gl/iHtse0
開通過程只是打開App輸入帳密點一下開通這樣而已。
除此之外還需要使用自然人憑證登入王道銀行網路銀行
王道銀行網路銀行:https://goo.gl/hux9tD
左邊個人設定->帳戶升級,也是點一點而已
然後把錢存進去就可以刷卡了~

腳踏車

進入APP首頁之後會有地圖,地圖上可以明顯地看到腳踏車位置,如果沒有看到腳踏車有可能是你的位置附近沒有,試著把地圖移動到熱鬧的地區就可以看見了。
程序中很明顯有一個掃馬開鎖,找到腳踏車掃馬就可以騎走了。
記得開藍芽,並且不要關閉
腳踏車長這個樣子。
會有兩個地方可以掃馬車頭與車尾
對著他們掃描,開鎖需要一點時間大概10秒左右
第一天免費,隨便你騎

停車

這裡官方上是說找腳踏車專用停車格停,不過實際上他們公司補車的時候更多的時候是直接把新車放在機車停車格上的。
再來,等你實際騎乘之後APP上其實會貼心地告訴你,只要停在非紅線處且不干擾到別人的地方即可。
亂停會被扣信用分數,不過我猜這裏扣分應該是你太誇張那台車子被檢舉,公司不得不出人來把車子回收才扣分的,應該不至於是GPS定位扣分,可以放心停概率不是太高。
然後大家比較有疑慮的可能是,如果我要去吃飯之類的暫時性的停一下子等等還要騎乘可以鎖車嗎?
這裡他的機能是一但鎖定之後就結束騎乘了,不會繼續收費,要卡位的話鎖定之後到APP點擊你的那台車子可以按預約,可以卡位10分鐘。
鎖定的時候記得手機要開藍芽要等一下,也是差不多時間手機畫面會出現騎乘結束,這樣才能安心離開。
建議騎乘時藍芽不要關,不會太耗電,騎完在關就好了。