Opencv学習ノート
27559 ワード
Opencv学習ノート
ラベル(スペース区切り):学習ノート
(1)操作画素
1.1ピクセル値のインデックス
1.1.1次元マトリクス
初期化マトリクスの行
1.1.2多次元マトリクス(RGB画像を例に)
注意:opencvには、2要素ベクトルと4要素ベクトルタイプ(cv::Vec 2 bとcv::Vec 4 b)があります.同様に、sはshort、iはint、fはfloat、dはdoubleなどの他のデータタイプもあります.これらのタイプはすべてテンプレートクラスcv::Vectを使用します.
1.1.3拡張
CV::Matのメンバー関数の戻り値タイプは、呼び出し時にテンプレートパラメータで指定する必要があります.したがってopencvはクラスcv::Mat_,このようなポインタまたは参照は、直接入力相互タイプ変換できます.このクラスは()オペレータを再ロードしました.例:
1.1.4プログラム運用:RGB画像にパプリカノイズを加える
1.2ポインタを使用して画像を巡回する
1.2.1 RGBピクチャopencvでの記憶方式
画像バッファの前の3バイトは画像左上隅画素の3チャネル値に対応し、次の3バイトは第1行の第2画素に対応する.
1.2.2入出力パラメータの使用
画像を処理するときに、画像を変更したくない場合は、画像の「深いコピー」を作成できます.
またはcreate関数を使用して、入力画像のサイズとタイプと同じマトリクスを作成します.
注意:create関数で作成された画像のメモリは連続しており、create関数では画像が埋められません.画像を巡回するには、2つのポインタを使用して完了する必要があります.
1.2.3下位ポインタ演算
cv::Mat形式のマトリクスのメモリ内の格納ヘッダアドレスは、dataメンバー変数によって得ることができ、dataはunsigned cahr型のポインタである:
現在の行から次の行に進むには、ポインタの幅を上げることで、次のことができます.
i行j列の画素アドレスは、次の行コードで呼び出すことができる
1.3反復器を使用して画像を巡回する
画像の反復器は、次のように宣言できます.
または
1.3.1反復器を使用して画像のすべてのピクセルを巡回
1.3.2効率的な画像遍歴サイクル
1.3.3画像と隣接領域を巡る操作
1.3.4多次元マトリクスを階層的に引き出す
1.3.5関心領域の定義
方法1:cv::Rect cv::Rectを使用するには、長方形の左上隅の座標(コンストラクション関数の最初の2つのパラメータ)と長方形の長さ幅(コンストラクション関数の後の2つのパラメータ)を指定する必要があります.方法2:cv::Range cv::Range
方法3:原図に直接定義する
(2)クラスベースの画像処理
2.1対象向けプログラミング思想
2.1.1例のプログラム:画像に所与の色を含むすべての画素を同定し、同じ画素255、他の画素0を与える2値画像を返す.
テストプログラム
処理結果
![出力効果図][2]
2.2画像空間の変換
(3)ヒストグラムを用いて画素を統計する
3.1ヒストグラムを統計して表示する
3.1.1ヒストグラム統計クラス
3.1.2テスト関数
次のような結果が表示されます.
####3.1.3二値画像を生成する閾値関数
ラベル(スペース区切り):学習ノート
(1)操作画素
1.1ピクセル値のインデックス
1.1.1次元マトリクス
if(iamge.channels()==1)
{
image.at<uchar>(i,j);
}
初期化マトリクスの行
result.row(0).setTo(cv::Scalar(0));//
result.row(result.rows - 1).setTo(cv::Scalar(0));
result.col(0).setTo(cv::Scalar(0));
result.col(result.cols - 1).setTo(cv::Scalar(0));
1.1.2多次元マトリクス(RGB画像を例に)
if(image.channels()==3)
{
image.at<cv::Vec3b>(i,j)[0]=255;
image.at<cv::Vec3b>(i,j)[1]=255;
image.at<cv::Vec3b>(i,j)[2]=255;
//
}
注意:opencvには、2要素ベクトルと4要素ベクトルタイプ(cv::Vec 2 bとcv::Vec 4 b)があります.同様に、sはshort、iはint、fはfloat、dはdoubleなどの他のデータタイプもあります.これらのタイプはすべてテンプレートクラスcv::Vectを使用します.
1.1.3拡張
CV::Matのメンバー関数の戻り値タイプは、呼び出し時にテンプレートパラメータで指定する必要があります.したがってopencvはクラスcv::Mat_,このようなポインタまたは参照は、直接入力相互タイプ変換できます.このクラスは()オペレータを再ロードしました.例:
cv::Mat_ impointer=image;//impointer image;
impointer(50,100)=0;// 50 ,100 ;
1.1.4プログラム運用:RGB画像にパプリカノイズを加える
void Salt(cv::Mat &image, int n)
{
for (int k = 0; k < n; ++k)
{
//rand()
int i = rand() % image.rows;
int j = rand() % image.cols;
if (image.channels() == 1)//
{
image.at(i, j) = 255;
}
if (image.channels() == 3)//
{
image.at<:vec3b>(i, j)[0] = 255;
image.at<:vec3b>(i, j)[1] = 255;
image.at<:vec3b>(i, j)[2] = 255;
}
}
}
1.2ポインタを使用して画像を巡回する
1.2.1 RGBピクチャopencvでの記憶方式
画像バッファの前の3バイトは画像左上隅画素の3チャネル値に対応し、次の3バイトは第1行の第2画素に対応する.
1.2.2入出力パラメータの使用
画像を処理するときに、画像を変更したくない場合は、画像の「深いコピー」を作成できます.
iamge=cv::imread("baboon.png");
//
cv::Mat imageClone=image.clone();
またはcreate関数を使用して、入力画像のサイズとタイプと同じマトリクスを作成します.
image.create(image.rows,image.cols,image.type());
注意:create関数で作成された画像のメモリは連続しており、create関数では画像が埋められません.画像を巡回するには、2つのポインタを使用して完了する必要があります.
for(int i=0;i// i
const uchar*data_in=image.ptr<uchar>(i);
uchar* data_out=result.ptr<uchar>(i);
for(int j=0;j//
}
}
1.2.3下位ポインタ演算
cv::Mat形式のマトリクスのメモリ内の格納ヘッダアドレスは、dataメンバー変数によって得ることができ、dataはunsigned cahr型のポインタである:
uchar* data =image.data;
現在の行から次の行に進むには、ポインタの幅を上げることで、次のことができます.
data += iamge.step;
i行j列の画素アドレスは、次の行コードで呼び出すことができる
data = image.data+i*image.step+j*image.elemSize();
// (i*cols+j), :i*image.step, +j*image.elemSize()
1.3反復器を使用して画像を巡回する
画像の反復器は、次のように宣言できます.
cv::MatIterator_::Vec3b>it;
または
cv::Mat_::Vec3b>::iterator it;
1.3.1反復器を使用して画像のすべてのピクセルを巡回
//
cv::Mat_<:vec3b>::iteraator it = image.begin<:vec3b>();
//
cv::Mat_<:vec3b>::iterator itend = image.end<:vec3b>();
//
for(;it!=itend;++it)
{
(*it)[0]=...;
(*it)[1]=...;
(*it)[2]=...;
}
1.3.2効率的な画像遍歴サイクル
void colorReduce(cv::Mat &image, int div = 64)
{
int nl = image.rows;
int nc = image.cols;
//
if (image.isContinuous())
{
nc = nc*nl;//
nl = 1;
}
int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));
uchar mask = 0xFF << n;
for (int i = 0; i < nl; i++)
{
ucahr* data = image.ptr(j);
for (int i = 0; i < nc; i++)
{
//
*data++ = *data&mask + dic / 2;
*data++ = *data&mask + div / 2;
*data++ = *data&mask + div / 2;
}
}
}
1.3.3画像と隣接領域を巡る操作
void sharpen(const cv::Mat &image, cv::Mat &result)
{
result.create(image.size(), image.type());
for (int i = 1; i < image.rows - 1; i++)//
{
const uchar* previous = image.ptr<const uchar>(i - 1);//
const uchar* current = image.ptr<const uchar>(i);//
const uchar* next = image.ptr<const uchar>(i + 1);//
uchar *output = result.ptr<uchar>(i);//
for (int j = 1; j < image.cols - 1; j++)
{
*output = cv::saturate_cast<uchar>(5*current[j]-current[j-1]-current[j+1]-previous[j]-next[j]);
output++;
}
}
// 0
result.row(0).setTo(cv::Scalar(0));
//
result.row(result.rows - 1).setTo(cv::Scalar(0));
result.col(0).setTo(cv::Scalar(0));
result.col(result.cols - 1).setTo(cv::Scalar(0));
}
1.3.4多次元マトリクスを階層的に引き出す
int main()
{
cv::Mat image;
image = cv::imread("baboon.png");
std::vector::Mat>planes;
cv::split(image, planes);
cv::namedWindow("channel1");
cv::imshow("channel1", planes[0]);
cv::namedWindow("channel2");
cv::imshow("channel2", planes[1]);
cv::namedWindow("channel3");
cv::imshow("channel3", planes[2]);
cv::waitKey(0);
}
1.3.5関心領域の定義
方法1:cv::Rect cv::Rectを使用するには、長方形の左上隅の座標(コンストラクション関数の最初の2つのパラメータ)と長方形の長さ幅(コンストラクション関数の後の2つのパラメータ)を指定する必要があります.方法2:cv::Range cv::Range
//270,385 ,logo.rows logo.cols
cv::Mat imageROI = image(cv::Range(270,270+logo.rows),cv::Range(385,385+logo.cols))
方法3:原図に直接定義する
start,end
cv::Mat imageROI = image.rowRange(start,end);
cv::Mat imageROI = image.colRange(start,end);
(2)クラスベースの画像処理
2.1対象向けプログラミング思想
2.1.1例のプログラム:画像に所与の色を含むすべての画素を同定し、同じ画素255、他の画素0を与える2値画像を返す.
//
class ColorDetector
{
private:
int minDist;
cv::Vec3b target;
cv::Mat result;
public:
//
ColorDetector() :minDist(100){
//
target[0] = target[1] = target[2] = 0;
}
cv::Mat process(const cv::Mat &image);
int getDistance(const cv::Vec3b & color)const;
void setColorDistanceThreshold(int distance);
int setColorDistanceThreshold()const;
void setTargetColor(unsigned char red, unsigned char green, unsigned char blue);
cv::Vec3b getTargetColor()const;
~ColorDetector(){};
};
cv::Vec3b ColorDetector::getTargetColor()const
{
return target;
}
void ColorDetector::setTargetColor(unsigned char red, unsigned char green, unsigned char blue)
{
//BGR
target[2] = red;
target[1] = green;
target[0] = blue;
}
void ColorDetector::setColorDistanceThreshold(int distance)
{
if (distance < 0)
{
distance = 0;
}
minDist = distance;
}
int ColorDetector::setColorDistanceThreshold()const
{
return minDist;
}
int ColorDetector::getDistance(const cv::Vec3b & color)const
{
return abs(color[0] - target[0]) + abs(color[1] - target[1]) + abs(color[2] - target[2]);
}
cv::Mat ColorDetector::process(const cv::Mat &image)
{
//
// ,
result.create(image.rows, image.cols, CV_8U);
//
cv::Mat_<:vec3b>::const_iterator it = image.begin<:vec3b>();
cv::Mat_<:vec3b>::const_iterator itend = image.end<:vec3b>();
cv::Mat_::iterator itout = result.begin();
//
for (; it != itend; it++, itout++)
{
//
if (getDistance(*it) < minDist)
{
*itout = 255;
}
else
{
*itout = 0;
}
}
return result;
}
テストプログラム
int main()
{
//
ColorDetector cdetect;
//
cv::Mat image = cv::imread("boldt.jpg");
if (!image.data)
return 0;
//
cdetect.setTargetColor(130,190,230);
cv::namedWindow("result");
//
cv::imshow("result", cdetect.process(image));
cv::waitKey();
return 0;
}
処理結果
![出力効果図][2]
2.2画像空間の変換
//RGB LAB
cv::cvtColor(image,converted,CV_BGR2Lab);
//RGB YCbCr
cv::cvtColor(image,converted,CV_BGR2YCrCb);
//RGB HSV
cv::cvtColor(image,converted, CV_BGR2HSV);
//RGB
cv::cvtColor(color,gray,CV_BGR2Gray);
(3)ヒストグラムを用いて画素を統計する
3.1ヒストグラムを統計して表示する
3.1.1ヒストグラム統計クラス
class Histgram1D
{
private:
// 、 、
int hist_size[1];
float hist_range[2];
const float* ranges[1];
int channels[1];
public:
// 1D ,
Histgram1D()
{
hist_size[0] = 256;
hist_range[0] = 0.0;
hist_range[1] = 255.0;
ranges[0] = hist_range;
channels[0] = 0;
}
//
cv::MatND getHistgram(const cv::Mat & image)
{
cv::MatND hist;
// calcHist
cv::calcHist(&image, //
1, //
channels, //
cv::Mat(), //
hist, //
1, //1D
hist_size, //
ranges //
);
return hist;
}
//
cv::Mat getHistgramImage(const cv::Mat & image)
{
//
cv::MatND hist = getHistgram(image);
//
double max_value = 0;
double min_value = 0;
cv::minMaxLoc(hist, &min_value, &max_value, 0, 0);
//
// 256*256, , uchar, 255
cv::Mat histImg(hist_size[0], hist_size[0], CV_8U, cv::Scalar(255));
// nbins 90%
int high_pointer = static_cast<int>(0.9*hist_size[0]);
//
for (int i = 0; i < hist_size[0]; i++)
{
float bin_value = hist.at<float>(i);//
//
int intensity = static_cast<int>(bin_value*high_pointer / max_value);
//
cv::line(histImg, cv::Point(i, hist_size[0]),
cv::Point(i, hist_size[0] - intensity),
cv::Scalar::all(0));
}
return histImg;
}
};
3.1.2テスト関数
int main()
{
cv::Mat image = cv::imread("lena.bmp", 0);
if (!image.data)
{
//
std::cout << "can not open this image!" << std::endl;
exit(0);
}
// Histgram1D
Histgram1D CalcHist;
//
cv::Mat histo = CalcHist.getHistgramImage(image);
//
/*for (int i = 0; i < 256; i++)
{
std::cout << "Count[" << i << "]=" << histo.at(i) << std::endl;
}*/
//
cv::namedWindow("Histgram");
cv::imshow("Histgram", histo);
cv::waitKey(0);
}
次のような結果が表示されます.
####3.1.3二値画像を生成する閾値関数
cv::Mat thresholded;
cv::threshold(image,thresholded,60,255,cv::THRESH_BINARY);
//( , , , , )