OpenCVを使ってある色以外は白黒にしてみる。

OpenCVを使ってある色以外は白黒にしてみる。

よくある処理に、ある色のみカラーにして他の色は白黒にして
ちょっと雰囲気のある写真にしたててみる。

オレンジ色のみ残して他の色を無くす(グレースケール)にしてみた。
ある色といってもRGBの数値でオレンジと示されても人間にはわからんので
直観的ででわかりやすいHSV色空間へいったん変更する。

https://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93
OpenCVでは色相(Hue)は0 - 180の範囲なので注意!!

HSV色空間へ変換した画像の色相(Hue)0〰20くらいまでのピクセル以外の
他の色のピクセルを全て彩度(Saturation)を0にすると色が無くなるのでグレースケールになる。
HSV色空間へ変換したあとRGB色空間へ戻すのをお忘れなく!!

//画面をだすよ
void display(cv::Mat image) {
    //名前をつける
    std::string windowName = "windowName";
    cv::namedWindow(windowName);
    //画面出た!!
    cv::imshow(windowName, image);
    //なにかキーをおして~
    cv::waitKey(1000 * 10);
    //整理整頓
    cv::destroyWindow(windowName);
}

//
// ここから
//
int main(int argc, char** argv) {

    cv::Mat image_ = cv::imread("fruits.jpg");
    cv::Mat ret_mat, hsv_image, dst_img;

    //HSV色空間へ
    cv::cvtColor(image_, hsv_image, CV_BGR2HSV);
    //HSV分解
    std::vector<cv::Mat> mat_channels;
    cv::split(hsv_image, mat_channels);

    //取り出す色を決定 0 - 20 まで
    int hue_min = 0;
    int hue_max = hue_min + 20;

    int hsv_value;
    int cols = hsv_image.cols;
    int rows = hsv_image.rows;
    for (int row = 0; row < rows; row++) {
        for (int col = 0; col < cols; col++) {
            hsv_value = static_cast<int>(mat_channels[0].at<uchar>(row, col));
            //色相(Hue)
            if (!((hue_min <= hsv_value) && (hsv_value <= hue_max))) {
                //彩度(Saturation)を0に
                mat_channels[1].at<uchar>(row, col) = 0;
            }
        }
    }
    //マージ
    cv::merge(mat_channels, dst_img);
    //RGB色空間へ (BGR)
    cv::cvtColor(dst_img, ret_mat, CV_HSV2BGR);

    //画面へ
    display(ret_mat);

    return 0;
}

オリジナル画像 f:id:treehitsuji:20170202175454j:plain

オレンジだけカラー画像 f:id:treehitsuji:20170202175458j:plain

円周率を計算する その3

前回の続き

円周率をPCで計算する。 実際、円周率計算ソフトなどをつかって円周率を求めることができるが
クラッチ状態から円周率プログラムを組んだことがなかったので実際にやってみた。

前回はdouble型の精度の問題で15桁までしか計算できなかった。 今回は多倍長ライブラリ(GMP)を使って任意の精度まで計算するように変更。
以下がそのソース。
digits 変数で任意に精度を設定 今回は 200 でやってみる。

続きを読む

円周率を計算する その2

前回の続き

円周率をPCで計算する。 実際、円周率計算ソフトなどをつかって円周率を求めることができるが
クラッチ状態から円周率プログラムを組んだことがなかったので実際にやってみた。

前回は一回しか計算できないプログラムなので 今回は n回 計算できるようにソースを改変 以下がそのソース。

続きを読む

円周率を計算する その1

円周率をPCで計算する。 実際、円周率計算ソフトなどをつかって円周率を求めることができるが
クラッチ状態から円周率プログラムを組んだことがなかったので実際にやってみた。

どうやって円周率を求めるのか、そのアルゴリズムを検索。
「円周率 アルゴリズム」でググってみると最初に出てくるのが

ガウス=ルジャンドルのアルゴリズム - Wikipedia

なるほど、 初期値

 \displaystyle
  a_0 = 1\\
  b_0=\frac{1}{\sqrt{2}}\\
  t_0 =\frac{1}{4}\\
  p_0 = 1\\

反復式

 \displaystyle
 a_{n+1}=\frac {a_{n}+b_{n}}{2}\\
 b_{n+1}=\frac {2}{\sqrt{a_nb_n}}\\
 t_{n+1}=t_n-p_n(a_n-a_{n+1})^2\\
 p_{n+1}=2p_n\\

を何回か繰り返して

PIを計算

 \displaystyle
  \pi\approx\frac{(a+b)^2}{4t}

する。

ループなしで一回のみ計算(n+1回目のみ)してみて円周率をもとめてみた。
以下がそのソース。

続きを読む

OpenCVを使っ輪郭を書いてみる

輪郭とは~~。となりのピクセルの差が大きいところ。 でこうなる。

//画面をだすよ
void display(cv::Mat image) {
    //まえの記事をみてね
}

//
// ここから
//
int main(int argc, char** argv) {

    cv::Mat opencv = cv::imread("OpenCv.png",0);
    cv::Mat image  = cv::Mat::zeros(opencv.rows, opencv.cols, CV_8UC1);

     uchar up,down,left,right;
     uchar upleft,downleft;
     uchar upright,downright;
     uchar anchor;

     int cols = opencv.cols;
     int rows = opencv.rows;

     for (int j = 1; j < rows  - 1; j++) {
         for (int i = 1; i < cols  - 1; i++) {
             up = lena.at<uchar>(j - 1, i);
             down = lena.at<uchar>(j + 1, i);
             left = lena.at<uchar>(j, i - 1);
             right = lena.at<uchar>(j, i + 1);

             upleft = lena.at<uchar>(j - 1, i-1);
             upright = lena.at<uchar>(j - 1, i+1);
             downleft = lena.at<uchar>(j + 1, i-1);
             downright = lena.at<uchar>(j + 1, i+1);

             anchor = lena.at<uchar>(j, i);

             image.at<uchar>(j, i) =
                         cv::saturate_cast<uchar>(
                                 anchor*-4
                                 +up*1
                                 +down*1
                                 +left*1
                                 +right*1
                                 +upleft*0
                                 +upright*0
                                 +downleft*0
                                 +downright*0
                 );
         }
     }

    //画面に出して!!
    display(image);

}

オリジナル画像

f:id:treehitsuji:20150211150256p:plain

輪郭画像

f:id:treehitsuji:20150211150320p:plain

OpenCVを使ってLenaさんを拡大する2。

前回は隙間が黒かったので今度は隙間を埋めてさらに
ぼかしをいれてなめらか拡大Lenaさんにしてみる。

//画面をだすよ
void display(cv::Mat image) {
    //まえの記事をみてね
}

//
// ここから
//
int main(int argc, char** argv) {
    //lenaさん登場!!
    cv::Mat lena = cv::imread("lena.jpg");
    //lenaさん白黒レトロ
    cv::cvtColor(lena, lena, CV_RGB2GRAY);
    //lenaさんの2倍のサイズの画像
    cv::Mat image  = cv::Mat::zeros(lena.cols * 2, lena.rows * 2, CV_8UC1);

    int cols = lena.cols;
    int rows = lena.rows;
    for (int j = 1; j < rows - 1 ; j++) {
        for (int i = 1; i < cols - 1; i++) {
            for (int k = -1; k < 2; k++) {
        //八方の隙間を同じ色でぬる!!
                for (int l = -1; l < 2; l++) {
                    image.at<uchar>(j*2 - k, i*2 - l) = cv::saturate_cast<uchar>(lena.at<uchar>(j, i));
                }
            }
        }
    }

    //ガウスぼかし!!でごまかし!!
     uchar up,down,left,right;
     uchar upleft,downleft;
     uchar upright,downright;
     uchar anchor;

     //lenaさんの2倍のサイズの画像
     cv::Mat image2  = cv::Mat::zeros(lena.cols * 2, lena.rows * 2, CV_8UC1);
     for (int j = 1; j < rows * 2 - 1; j++) {
         for (int i = 1; i < cols * 2 - 1; i++) {
             up = image.at<uchar>(j - 1, i);
             down = image.at<uchar>(j + 1, i);
             left = image.at<uchar>(j, i - 1);
             right = image.at<uchar>(j, i + 1);

             upleft = image.at<uchar>(j - 1, i-1);
             upright = image.at<uchar>(j - 1, i+1);
             downleft = image.at<uchar>(j + 1, i-1);
             downright = image.at<uchar>(j + 1, i+1);
             anchor = image.at<uchar>(j, i);

             image2.at<uchar>(j, i) =
                         cv::saturate_cast<uchar>(
                                 anchor*4/16
                                 +up*2/16
                                 +down*2/16
                                 +left*2/16
                                 +right*2/16
                                 +upleft*1/16
                                 +upright*1/16
                                 +downleft*1/16
                                 +downright*1/16
                 );
         }
     }

    //画面に出して!!
    display(image2);
}

2倍Lenaさん

f:id:treehitsuji:20150208185143p:plain

OpenCVを使ってLenaさんを拡大する。

こんどはLenaさんを拡大してみる。
縦の0行目と1行目の間に1行追加、1行目と2行目の間に1行追加・・・・・・
横の0列目と1列目の間に1列追加、1列目と2列目の間に1列追加・・・・・・
広げてみた。

//画面をだすよ
void display(cv::Mat image) {
    //まえの記事をみてね
}

//
// ここから
//
int main(int argc, char** argv) {
    //lenaさん登場!!
    cv::Mat lena = cv::imread("lena.jpg");
    //lenaさん白黒レトロ
    cv::cvtColor(lena, lena, CV_RGB2GRAY);
    //lenaさんの2倍のサイズの画像
    cv::Mat image  = cv::Mat::zeros(lena.cols * 2, lena.rows * 2, CV_8UC1);

    int cols = lena.cols;
    int rows = lena.rows;
    for (int j = 0; j < rows ; j++) {
        for (int i = 0; i < cols; i++) {
            image.at<uchar>(j*2, i*2) = cv::saturate_cast<uchar>(lena.at<uchar>(j, i));
        }
    }
    //画面に出して!!
    display(image);
}

なんか変!!

f:id:treehitsuji:20150208181136p:plain