C++で実装する画像スムーザー:周囲8ピクセルとの平均値で画像を平滑化する方法
ここでは、画像のグレースケール値を表す2次元行列 M が与えられたとき、各ピクセルの値を「自分自身と周囲8ピクセルのグレースケール値の平均(小数点以下は切り捨て)」に置き換えるスムーザー(平滑化フィルタ)を設計します。なお、端や角にあるセルのように周囲のセルが8個より少ない場合は、存在するすべてのピクセルを使って平均を計算します。
問題の例
たとえば、次のような入力が与えられたとします。
| 1 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
この場合、出力は次のようになります。
| 0 | 0 | 0 |
| 0 | 0 | 0 |
| 0 | 0 | 0 |
中央の0以外のピクセルは、それぞれ自分自身を含む9マスの平均が 8/9 ≒ 0.88 となり、切り捨てると0になるためです。
解法のアプローチ
この問題は、以下の手順で解くことができます。
- R を M の行数、C を M の列数とします。
- 隣接方向を表す配列 d = { -1, 0, 1 } を定義します。
- 結果を格納するための R × C サイズの2次元配列 res を用意します。
- i を 0 から R-1 まで繰り返します。
- j を 0 から C-1 まで繰り返します。
- sum := 0、count := 0 で初期化します。
- k を 0 から 2 まで繰り返します。
- l を 0 から 2 まで繰り返します。
- m := i + d[k]、n := j + d[l] として隣接セルの座標を求めます。
- m と n が行列の範囲内(m ≥ 0 かつ m < R かつ n ≥ 0 かつ n < C)であれば、count を1増やし、sum に M[m][n] を加算します。
- l を 0 から 2 まで繰り返します。
- res[i][j] := sum / count(整数除算により切り捨て)とします。
- j を 0 から C-1 まで繰り返します。
- 最後に res を返します。
C++による実装例
理解を深めるために、実際のC++コードを見てみましょう。
#include <bits/stdc++.h>
using namespace std;
void print_vector(vector<vector<auto> > v){
cout << "[";
for(int i = 0; i<v.size(); i++){
cout << "[";
for(int j = 0; j <v[i].size(); j++){
cout << v[i][j] << ", ";
}
cout << "],";
}
cout << "]"<<endl;
}
class Solution {
public:
vector<vector<int>> imageSmoother(vector<vector<int>>& M) {
int R = M.size();
int C = M[0].size();
vector<int> d{ -1, 0, 1 };
vector<vector<int> > res(R, vector<int>(C, 0));
for (int i = 0; i < R; ++i) {
for (int j = 0; j < C; ++j) {
int sum = 0, count = 0;
for (int k = 0; k < 3; ++k) {
for (int l = 0; l < 3; ++l) {
int m = i + d[k], n = j + d[l];
if (m >= 0 && m < R && n >= 0 && n < C) ++count, sum += M[m][n];
}
}
res[i][j] = sum / count;
}
}
return res;
}
};
main(){
Solution ob;
vector<vector<int>> v = {{1,1,1},{1,0,1},{1,1,1}};
print_vector(ob.imageSmoother(v));
}入力
{{1,1,1},{1,0,1},{1,1,1}}出力
[[0, 0, 0],[0, 0, 0],[0, 0, 0]]
まとめ
このアルゴリズムは、オフセット配列 { -1, 0, 1 } を二重に組み合わせることで、各ピクセルとその周囲8方向を効率よく走査しています。計算量は O(R × C × 9)、つまり O(R × C) であり、画像サイズに対して線形時間で処理できます。境界チェックを行うことで、画像の端や角でも正しく平均値を計算できる点がポイントです。
-
C++とOpenCVで二値画像(バイナリイメージ)を反転する方法
二値画像(バイナリイメージ)の反転とは、ピクセル値を逆転させる処理のことです。視覚的な観点から見ると、二値画像を反転させると、白いピクセルは黒へ、黒いピクセルは白へと変換されます。この処理は、主に3つの関数を組み合わせて実現します。それぞれの手順を順番に見ていきましょう。ステップ1:カラー画像をグレースケールに変換するまず、cvtColor()関数を使って元の画像をグレースケール画像に変換します。この関数の基本形は次の通りです。cvtColor(original_image, grayscale_image, COLOR_BGR2GRAY);ステップ2:グレースケール画像を二値化する続いて、グ
-
C++とOpenCVでバイナリ画像(二値画像)を作成する方法を解説
バイナリ画像(二値画像)とは、黒と白の2色のみで表現されるデジタル画像のことです。画像処理の観点から見ると、バイナリ画像は「0」と「1」という2つの値しか持たないピクセルで構成されています。ピクセルの値が0の場合は純粋な黒を、値が1の場合は純粋な白を表します。グレースケール画像では、各ピクセルが256段階の異なる値を持つのに対し、バイナリ画像では2つの値しか存在しません。このシンプルさゆえに、バイナリ画像はさまざまな用途で活用されています。例えば、モルフォロジー変換(形態学的処理)ではバイナリ画像が必要であり、背景から物体の形状を抽出する処理にもバイナリ画像が用いられます。OpenCVを使用す