現在、作成中…
もくじ
- フィルタリング処理
- 幾何学変換
- 画素単位の変換
1. フィルタリング処理
1.1 平滑化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#include <opencv2/opencv.hpp> int main(void) { // 画像を格納するオブジェクトを宣言する cv::Mat src, dst1, dst2, dst3, dst4; // 画像ファイルから画像データを読み込む src = cv::imread("C:/opencv/sources/samples/data/board.jpg"); // 平均値フィルタ // # Size(x, y)でx方向、y方向のフィルタサイズを指定する cv::blur(src, dst1, cv::Size(7, 7)); // 中央値フィルタ cv::medianBlur(src, dst2, 7); // ガウシアンフィルタ // # Size(x, y)でx方向、y方向のフィルタサイズを指定する cv::GaussianBlur(src, dst3, cv::Size(7, 7), 0.0); // バイラテラルフィルタ cv::bilateralFilter(src, dst4, 20, 200, 20); // ウィンドウに画像を表示する cv::imshow("原画像", src); cv::imshow("平均値フィルタ", dst1); cv::imshow("中央値フィルタ", dst2); cv::imshow("ガウシアンフィルタ", dst3); cv::imshow("バイラテラルフィルタ", dst4); cv::waitKey(); return 0; } |
1.2 輪郭抽出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include <opencv2/opencv.hpp> int main(void) { // 画像を格納するオブジェクトを宣言する cv::Mat src, dst1, dst2, dst3, dst4, dst5, dst6; // 画像ファイルから画像データを読み込む // # 第2引数に IMREAD_GRAYSCALE を指定すると、グレイスケール画像に変換する src = cv::imread("C:/opencv/sources/samples/data/lena.jpg", cv::IMREAD_GRAYSCALE); // ラプラシアンフィルタ cv::Laplacian(src, dst1, -1); // Sobelフィルタ cv::Sobel(src, dst2, -1, 1, 0); // x方向 cv::Sobel(src, dst3, -1, 0, 1); // y方向 // Cannyフィルタ cv::Canny(src, dst4, 60.0, 150.0); // ウィンドウに画像を表示する cv::imshow("原画像", src); cv::imshow("ラプラシアンフィルタ", dst1); cv::imshow("Sobelフィルタ x方向", dst2); cv::imshow("Sobelフィルタ y方向", dst3); cv::imshow("Cannyフィルタ", dst4); cv::waitKey(); return 0; } |
1.3 濃淡変換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include <opencv2/opencv.hpp> int main(void) { // 画像を格納するオブジェクトを宣言する cv::Mat src, dst1, dst2; // 画像ファイルから画像データを読み込む src = cv::imread("C:/opencv/sources/samples/data/lena.jpg", cv::IMREAD_GRAYSCALE); // ヒストグラム平坦化 cv::equalizeHist(src, dst1); // ルックアップテーブルを用いたガンマ補正 double gamma = 1.5; // ガンマ値 uchar lut[256]; // ルックアップテーブル用配列 for (int i = 0; i < 256; i++) { lut[i] = pow(i / 255.0, 1 / gamma) * 255.0; // ガンマ補正式 } cv::LUT(src, cv::Mat(1, 256, CV_8UC1, lut), dst2); // ルックアップテーブル変換 // ウィンドウに画像を表示する cv::imshow("原画像", src); cv::imshow("ヒストグラム平坦化", dst1); cv::imshow("ガンマ補正", dst2); cv::waitKey(); return 0; } |
1.4 2値化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include <opencv2/opencv.hpp> int main(void) { // 画像を格納するオブジェクトを宣言する cv::Mat src, dst1, dst2, dst3, dst4; // 画像ファイルから画像データを読み込む src = cv::imread("C:/opencv/sources/samples/data/lena.jpg", cv::IMREAD_GRAYSCALE); // 2値化処理 // # 2値化閾値 = 140, 変換後の最大値 = 255 cv::threshold(src, dst1, 140, 255, cv::THRESH_BINARY); // 2値化処理(判別分析2値化法(大津の方法)) // # 最適な閾値を自動的に算出する cv::threshold(src, dst2, 0, 255, cv::THRESH_OTSU); // 膨張処理(最大値フィルタ) cv::dilate(dst2, dst3, cv::Mat()); // 収縮処理(最小値フィルタ) cv::erode(dst2, dst4, cv::Mat()); cv::imshow("原画像", src); cv::imshow("2値化処理", dst1); cv::imshow("2値化処理(大津の方法)", dst2); cv::imshow("膨張処理", dst3); cv::imshow("収縮処理", dst4); cv::waitKey(); return 0; } |
1.5 非写実的レンダリング
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#include <opencv2/opencv.hpp> int main(void) { // 画像を格納するオブジェクトを宣言する cv::Mat src, dst1, dst2, dst3, dst4, dst5; // 画像ファイルから画像データを読み込む src = cv::imread("C:/opencv/sources/samples/data/butterfly.jpg", cv::IMREAD_COLOR); if (src.empty() == true) { // 画像データが読み込めなかったときは終了する return 0; } // 非写実的レンダリング float sigma_s = 60.0; // 0~200 float sigma_r = 0.07; // 0~1 float shade_factor = 0.02; // 0~0.1 std::cout << "鉛筆画風 処理中..." << std::endl; cv::pencilSketch(src, dst1, dst2, sigma_s, sigma_r, shade_factor); sigma_s = 60.0; // 0~200 sigma_r = 0.5; // 0~1 std::cout << "スタライズ 処理中..." << std::endl; cv::stylization(src, dst3, sigma_s, sigma_r); sigma_s = 10.0; // 0~200 sigma_r = 0.15; // 0~1 std::cout << "細部強調 処理中..." << std::endl; cv::detailEnhance(src, dst4, sigma_s, sigma_r); sigma_s = 60.0; // 0~200 sigma_r = 0.4; // 0~1 std::cout << "エッジ保存平滑化 処理中..." << std::endl; cv::edgePreservingFilter(src, dst5, 1, sigma_s, sigma_r); // ウィンドウに画像を表示する cv::imshow("原画像", src); cv::imshow("鉛筆画風(モノクロ)", dst1); cv::imshow("鉛筆画風(カラー)", dst2); cv::imshow("スタライズ", dst3); cv::imshow("細部強調", dst4); cv::imshow("エッジ保存平滑化", dst5); // 何かキーが押されるまで待つ cv::waitKey(); return 0; } |
2. 幾何学変換
2.1 アフィン変換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <opencv2/opencv.hpp> int main(void) { cv::Mat src, dst; src = cv::imread("C:/opencv/sources/samples/data/lena.jpg"); // アフィン変換行列(2行3列) cv::Mat affine = (cv::Mat_<double>(2, 3) << 0.8, 0, 0, 0, 1.5, 0); // アフィン変換 // # warpAffine(原画像, 変換後画像, 変換後画像サイズ, 補間方法) // # INTER_LINEAR 線形補間(バイリニア) // INTER_NEAREST 再近傍補間 // INTER_CUBIC バイキュービック補間 // INTER_LANCZOS4 Lanczos(ランチョス)補間 cv::warpAffine(src, dst, affine, src.size(), cv::INTER_LINEAR); cv::imshow("原画像", src); cv::imshow("変換後画像", dst); cv::waitKey(); return 0; } |
2.2 対応点からアフィン変換行列を算出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <opencv2/opencv.hpp> int main(void) { cv::Mat src, dst; src = cv::imread("C:/opencv/sources/samples/data/lena.jpg"); // アフィン変換行列 cv::Mat affine; // 対応点(3点)の設定 // # 0.8f の f は直前の数値がfloat型であることを示す。 // fをつけない実数定数はdouble型になる。 cv::Point2f srcPoint[3] = { { 0, 0 },{ 1, 0 },{ 0, 1 } }; cv::Point2f dstPoint[3] = { { 0, 0 },{ 0.8f, 0.2f },{ 0.2f, 0.8f } }; // 対応点からアフィン変換行列を求める // # srcPoint から dstPoint への変換を行うアフィン変換行列が得られる。 affine = cv::getAffineTransform(srcPoint, dstPoint); // アフィン変換 cv::warpAffine(src, dst, affine, src.size(), cv::INTER_LINEAR); cv::imshow("原画像", src); cv::imshow("変換後画像", dst); cv::waitKey(); return 0; } |
2.3 射影変換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <opencv2/opencv.hpp> int main(void) { cv::Mat src, dst; src = cv::imread("C:/opencv/sources/samples/data/lena.jpg"); // ホモグラフィ行列(3行3列) cv::Mat homography = (cv::Mat_<double>(3, 3) << 0.8, -0.2, 180, 0.4, 0.9, 40, 0.001, 0.0001, 1); // 射影変換 cv::warpPerspective(src, dst, homography, src.size(), cv::INTER_LINEAR); cv::imshow("原画像", src); cv::imshow("変換後画像", dst); cv::waitKey(); return 0; } |
2.4 立方体の面への画像の貼り付け
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#include <opencv2/opencv.hpp> int main(void) { cv::Mat src, dst; src = cv::imread("C:/opencv/sources/samples/data/lena.jpg"); // 射影変換行列 cv::Mat homography1, homography2, homography3; // 対応点の設定 // # destPointは、立方体の三つの面の各頂点を2次元平面に投影した座標 float w = src.cols - 1, h = src.rows - 1; cv::Point2f srcPoint[4] = { { 0, 0 },{ w, 0 },{ w, h },{ 0, h } }; cv::Point2f dstPoint1[4] = { { 25, 100 },{ 230, 45 },{ 362, 60 },{ 195, 150 } }; cv::Point2f dstPoint2[4] = { { 25, 100 },{ 195, 150 },{ 225, 370 },{ 85, 285 } }; cv::Point2f dstPoint3[4] = { { 195, 150 },{ 362, 60 },{ 350, 215 },{ 225, 370 } }; // 対応点から射影変換行列を求める(srcPoint → dstPoint1) homography1 = cv::getPerspectiveTransform(srcPoint, dstPoint1); homography2 = cv::getPerspectiveTransform(srcPoint, dstPoint2); homography3 = cv::getPerspectiveTransform(srcPoint, dstPoint3); // 射影変換 // # BORDER_TRANSPARENT 変換後画像を初期化しないで上書きする cv::warpPerspective(src, dst, homography1, cv::Size(400, 400), cv::INTER_LINEAR); cv::warpPerspective(src, dst, homography2, cv::Size(400, 400), cv::INTER_LINEAR, cv::BORDER_TRANSPARENT); cv::warpPerspective(src, dst, homography3, cv::Size(400, 400), cv::INTER_LINEAR, cv::BORDER_TRANSPARENT); // 立方体の辺を描く for (int i = 0; i < 4; i++) { cv::line(dst, dstPoint1[i], dstPoint1[(i + 1) & 3], cv::Scalar::all(255), 1, cv::LINE_AA); cv::line(dst, dstPoint2[i], dstPoint2[(i + 1) & 3], cv::Scalar::all(255), 1, cv::LINE_AA); cv::line(dst, dstPoint3[i], dstPoint3[(i + 1) & 3], cv::Scalar::all(255), 1, cv::LINE_AA); } cv::imshow("原画像", src); cv::imshow("立方体へのマッピング", dst); cv::waitKey(); return 0; } |
2.5 マウスを使って画像を自由に変形する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
#include <opencv2/opencv.hpp> // 射影変換のための各情報を保存する構造体 struct ImageInfo { cv::Mat src, dst; // 入力画像と出力画像 cv::Mat matrix; // 射影変換行列 cv::Point2f srcPt[4]; // 変換前の4頂点座標(左上, 右上, 右下, 左下) cv::Point2f dstPt[4]; // 変換後の4頂点座標(左上, 右上, 右下, 左下) std::string winName; // 出力ウインドウの名前 }; // コールバック関数 void mouseCallback(int event, int x, int y, int flags, void *data) { static int select = -1; // マウスで選択された頂点番号(-1:選択無し) cv::Point2f p(x, y); // マウスの座標 double dis = 1e10; ImageInfo &info = *(ImageInfo *)data; switch (event) { case cv::EVENT_LBUTTONDOWN: // 左ボタンを押したとき、4頂点のうち一番近い点を探す for (int i = 0; i < 4; i++) { double d = cv::norm(p - info.dstPt[i]); // 頂点iとマウス座標との距離を計算 if (d < 20 && d < dis) { select = i; dis = d; } } break; case cv::EVENT_RBUTTONDOWN: // 右ボタンを押したとき、ホモグラフィ行列を出力する std::cout << info.matrix << std::endl; break; case cv::EVENT_LBUTTONUP: // 左ボタンを離したとき、画像を射影変換してウインドウに表示する // 変換前後の座標からホモグラフィ行列を求める info.matrix = cv::getPerspectiveTransform(info.srcPt, info.dstPt); // 射影変換をする cv::warpPerspective(info.src, info.dst, info.matrix, info.dst.size(), cv::INTER_LINEAR); // ウインドウに表示する cv::imshow(info.winName, info.dst); select = -1; break; } if (flags & cv::EVENT_FLAG_LBUTTON && select > -1) { // マウスの左ボタンが押されている、かつ、頂点が選択されているとき、 // 選択されている頂点の座標を現在のマウスの位置にする info.dstPt[select] = p; // 画像範囲の枠を描く // 4頂点座標を cv::Point(整数座標)の vector に変換する // # polylines が cv::Point2f に対応していないため。 // # getPerspectiveTransform は cv::Point2f にしか対応していない。 std::vector<cv::Point> poly; for (int i = 0; i < 4; i++) { poly.push_back(cv::Point(info.dstPt[i])); } cv::Mat overlay(info.dst.size(), CV_8UC3); cv::polylines(overlay, poly, true, cv::Scalar::all(255), 3, cv::LINE_AA); // 変換後画像に枠線を重ねて表示する cv::imshow(info.winName, info.dst + overlay); } } int main(void) { // ウインドウのサイズ(変更可) cv::Size window(800, 800); // 射影変換のための画像情報構造体 ImageInfo info; // 画像を読み込む info.src = cv::imread("C:/opencv/sources/samples/data/butterfly.jpg", cv::IMREAD_COLOR); info.dst = cv::Mat(info.src.size(), CV_8UC3); // 原画像の4頂点座標 info.srcPt[0] = cv::Point2f(0, 0); info.srcPt[1] = cv::Point2f(info.src.cols - 1, 0); info.srcPt[3] = cv::Point2f(0, info.src.rows - 1); info.srcPt[2] = cv::Point2f(info.src.cols - 1, info.src.rows - 1); // 画像の縮小率を計算する(ウインドウ幅の1/2のサイズにする) double scale; if (info.src.cols > info.src.rows) { scale = double(window.width) / info.src.cols / 2; } else { scale = double(window.height) / info.src.rows / 2; } // コールバック関数を登録する info.winName = "射影変換お試し"; cv::namedWindow(info.winName); cv::setMouseCallback(info.winName, mouseCallback, (void *)&info); int key = 'r'; do { if (key == 'r') { // 変換後の4頂点座標(初期位置。画像サイズをウインドウの1/2にしてウインドウの中央に表示する) info.dstPt[0] = cv::Point2f((window.width - info.src.cols * scale) / 2, (window.height - info.src.rows * scale) / 2); info.dstPt[1] = cv::Point2f(info.src.cols - 1, 0) * scale + info.dstPt[0]; info.dstPt[3] = cv::Point2f(0, info.src.rows - 1) * scale + info.dstPt[0]; info.dstPt[2] = cv::Point2f(info.src.cols - 1, info.src.rows - 1) * scale + info.dstPt[0]; // 対応点から射影変換行列を求める(srcPoint → dstPoint1) info.matrix = cv::getPerspectiveTransform(info.srcPt, info.dstPt); // 射影変換をして画像を表示する cv::warpPerspective(info.src, info.dst, info.matrix, window, cv::INTER_LINEAR); cv::imshow(info.winName, info.dst); } key = cv::waitKey(); } while (key != 0x1b); return 0; } |
3. 画素単位の変換
3.1 グレイスケール画像の画素値の操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
#include <opencv2/opencv.hpp> int main(void) { // cv::Mat_<Type>で画像を格納するオブジェクトを宣言する // # グレイスケール画像は1画素あたり8bitのため、uchar型で宣言する cv::Mat_<uchar> src1, dst1; // 画像ファイルから画像データを読み込む // # src1は uchar型のデータしか入れられないため、imreadで読み込むときに画像をグレースケールに変換しておく src1 = cv::imread("C:/opencv/sources/samples/data/lena.jpg", cv::IMREAD_GRAYSCALE); // src1と同じ大きさで画像を作成する dst1 = cv::Mat_<uchar>(src1.size()); // 1画素ごとの変換 for (int y = 0; y < src1.rows; y++) { for (int x = 0; x < src1.cols; x++) { // srcの座標(x,y)の画素値を取り出す // # x座標は列番号、y座標は行番号にあたるため、(y,x)の並びなることに注意 uchar value = src1(y, x); // dst1(y,x)にsrc(y,x)の画素値を反転して書き込む dst1(y, x) = 255 - value; } } cv::imshow("原画像 src1", src1); cv::imshow("出力画像 dst1", dst1); // cv::Matで画像を格納するオブジェクトを宣言する cv::Mat src2, dst2; // 画像ファイルから画像データを読み込む // # グレイスケールで画像を読み込んだ場合、src2はuchar型に設定される。 src2 = cv::imread("C:/opencv/sources/samples/data/lena.jpg", cv::IMREAD_GRAYSCALE); // src2と同じ大きさ、型で画像を作成する dst2 = cv::Mat(src2.size(), src2.type()); // 1画素ごとの変換 for (int y = 0; y < src2.rows; y++) { for (int x = 0; x < src2.cols; x++) { // srcの座標(x,y)の画素値を取り出す // # x座標は列番号、y座標は行番号にあたるため、(y,x)の並びなることに注意 uchar value = src2.at<uchar>(y, x); // dst2(y,x)にsrc(y,x)の画素値を反転して書き込む dst2.at<uchar>(y, x) = 255 - value; } } cv::imshow("原画像 src2", src2); cv::imshow("出力画像 dst2", dst2); cv::waitKey(); return 0; } |
3.2 フルカラー画像の画素値の操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
#include <opencv2/opencv.hpp> int main(void) { // cv::Mat_<Type>で画像を格納するオブジェクトを宣言する // # フルカラー画像は1画素あたり8bit x 3channel(R,G,B)のため、cv::Vec3b型で宣言する // # cv::Vec3b に対応するtype値は CV_8UC3 cv::Mat_<cv::Vec3b> src1, dst1; // 画像ファイルから画像データを読み込む // # src1は Vec3b型のデータしか入れられないため、imreadで読み込むときに画像をフルカラーに変換しておく src1 = cv::imread("C:/opencv/sources/samples/data/lena.jpg", cv::IMREAD_COLOR); // src1と同じ大きさで画像を作成する dst1 = cv::Mat_<cv::Vec3b>(src1.size()); // 1画素ごとの変換 for (int y = 0; y < src1.rows; y++) { for (int x = 0; x < src1.cols; x++) { // srcの座標(x,y)の画素値を取り出す // # x座標は列番号、y座標は行番号にあたるため、(y,x)の並びなることに注意 // # channel番号は[]で指定する uchar blue = src1(y, x)[0]; // 青成分 uchar green = src1(y, x)[1]; // 緑成分 uchar red = src1(y, x)[2]; // 赤成分 // dst1(y,x)にsrc(y,x)の赤成分の画素値を半分にして書き込む dst1(y, x)[0] = blue; dst1(y, x)[1] = green; dst1(y, x)[2] = red / 2; // 上の3行は次のように1行で書くこともできる // dst1(y, x) = cv::Vec3b(blue, green, red / 2); } } cv::imshow("原画像 src1", src1); cv::imshow("出力画像 dst1", dst1); // cv::Matで画像を格納するオブジェクトを宣言する cv::Mat src2, dst2; // 画像ファイルから画像データを読み込む // # フルカラーで画像を読み込んだ場合、src2はcv::Vec3b型に設定される。 src2 = cv::imread("C:/opencv/sources/samples/data/lena.jpg", cv::IMREAD_COLOR); // src2と同じ大きさ、型で画像を作成する dst2 = cv::Mat(src2.size(), src2.type()); // 1画素ごとの変換 for (int y = 0; y < src2.rows; y++) { for (int x = 0; x < src2.cols; x++) { // srcの座標(x,y)の画素値を取り出す // # x座標は列番号、y座標は行番号にあたるため、(y,x)の並びなることに注意 uchar blue = src2.at<cv::Vec3b>(y, x)[0]; // 青成分 uchar green = src2.at<cv::Vec3b>(y, x)[1]; // 緑成分 uchar red = src2.at<cv::Vec3b>(y, x)[2]; // 赤成分 // dst1(y,x)にsrc(y,x)の赤成分の画素値を半分にして書き込む dst2.at<cv::Vec3b>(y, x)[0] = blue; dst2.at<cv::Vec3b>(y, x)[1] = green; dst2.at<cv::Vec3b>(y, x)[2] = red / 2; // 上の3行は次のように1行で書くこともできる // dst2.at<cv::Vec3b>(y, x) = cv::Vec3b(blue, green, red / 2); } } cv::imshow("原画像 src2", src2); cv::imshow("出力画像 dst2", dst2); cv::waitKey(); return 0; } |
3.3 フィルタリング処理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
#include <opencv2/opencv.hpp> int main(void) { // 画像を格納するオブジェクトを宣言する cv::Mat_<uchar> src, dst1, dst2; // 画像ファイルから画像データを読み込む src = cv::imread("C:/opencv/sources/samples/data/lena.jpg", cv::IMREAD_GRAYSCALE); // srcと同じサイズで画像を作成する。初期値を0にする。 dst1 = cv::Mat_<uchar>(src.size(), 0); dst2 = cv::Mat_<uchar>(src.size(), 0); // 平均値フィルタ // # 3x3フィルタをかけるので、画像の走査範囲を1画素狭くしている for (int y = 1; y < src.rows - 1; y++) { for (int x = 1; x < src.cols - 1; x++) { int value; value = src(y - 1, x - 1) + src(y - 1, x) + src(y - 1, x + 1) + src(y, x - 1) + src(y, x) + src(y, x + 1) + src(y + 1, x - 1) + src(y + 1, x) + src(y + 1, x + 1); value /= 9; dst1(y, x) = value; } } // 鮮鋭化フィルタ for (int y = 1; y < src.rows - 1; y++) { for (int x = 1; x < src.cols - 1; x++) { int value; value = - src(y - 1, x) - src(y, x - 1) + 5 * src(y, x) - src(y, x + 1) - src(y + 1, x); // saturate_cast<型>は、型の値域になるように値をまるめる。 // saturate_cast<uchar>(value)は、value>255 のときvalue=255になり、 // value<0 のときvalue=0になる。 dst2(y, x) = cv::saturate_cast<uchar>(value); } } cv::imshow("原画像", src); cv::imshow("平均値フィルタ", dst1); cv::imshow("鮮鋭化フィルタ", dst2); cv::waitKey(); return 0; } |
3.4 エンボス効果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <opencv2/opencv.hpp> int main(void) { // 画像を格納するオブジェクトを宣言する cv::Mat_<uchar> src, dst; // 画像ファイルから画像データを読み込む src = cv::imread("C:/opencv/sources/samples/data/lena.jpg", cv::IMREAD_GRAYSCALE); // srcと同じサイズで画像を作成する。初期値を0にする。 dst = cv::Mat_<uchar>(src.size(), 0); // エンボス効果 for (int y = 0; y < src.rows - 1; y++) { for (int x = 0; x < src.cols - 1; x++) { int value; value = src(y + 1, x + 1) - src(y, x) + 128; dst(y, x) = cv::saturate_cast<uchar>(value); } } cv::imshow("原画像", src); cv::imshow("エンボス効果", dst); cv::waitKey(); return 0; } |
3.5 球面変換と内挿計算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
#include <opencv2/opencv.hpp> int main(void) { // 画像を格納するオブジェクトを宣言する cv::Mat_<uchar> src, dst; // 画像ファイルから画像データを読み込む src = cv::imread("C:/opencv/sources/samples/data/sudoku.png", cv::IMREAD_GRAYSCALE); // srcと同じサイズで画像を作成する dst = cv::Mat_<uchar>(src.size(), 0); double cx = src.cols / 2; // 画像の中央座標(cx,cy) double cy = src.rows / 2; double radius = ((cx < cy) ? cx : cy) * 0.8; // 球の半径 radius for (int y = 0; y < src.rows; y++) { for (int x = 0; x < src.cols; x++) { double d = sqrt(pow(x - cx, 2) + pow(y - cy, 2)); if (d < radius) { // 球面変換の座標変換式 double ang = atan2(y - cy, x - cx); double r = asin(d / radius) / CV_PI * 2 * radius; double sx = cx + r * cos(ang); double sy = cy + r * sin(ang); // 画素の線形補間 int ix = (int)sx, iy = (int)sy; double px = sx - ix, py = sy - iy; double value = src(iy, ix) * (1 - px) * (1 - py) + src(iy, ix + 1) * px * (1 - py) + src(iy + 1, ix) * (1 - px) * py + src(iy + 1, ix + 1) * px * py; dst(y, x) = (uchar)value; } else { // 球の外側は変換なし dst(y, x) = src(y, x); } } } cv::imshow("原画像", src); cv::imshow("球面変換", dst); cv::waitKey(); return 0; } |