fc2ブログ

OpenCV 3.1で輪郭検出処理(findContours)を使う(2)

 前回、「最小矩形」と「楕円フィッティング」の2種類のうち、片方の処理のみでは希望する特徴量が得られないことについてお話ししました。その詳細を実際に画像処理した結果を用いて説明します。画像は、「円、三角形、四角形の3個を描画したもの」と前回の「楕円4個を描画したもの」の2種類用います。

 まずは、「最小矩形のみ」を用いた場合ですが、処理結果は以下の通りです。最小矩形のみ(形状)
最小矩形のみ(楕円) 中心座標は、描画される矩形の中心座標で、長さもその矩形をもとに算出されます。ところが、オブジェクトの傾き角度が希望の値にならず、変な値が入っていました。

 次に、「楕円フィッティングのみ」の結果は以下の通りです。楕円フィッティングのみ(形状)
楕円フィッティングのみ(楕円) 中心座標は、フィッティングした描画楕円の中心座標で、最小矩形の中心座標ではありません(当然と言えば当然ですが、そのような処理なんですね)。円と四角形では違いが出ませんが、三角形の中心座標が「最小矩形」で処理した中心座標よりも下側に出ました。
 また、長さはフィッティング楕円を囲む最小矩形から算出するため、円のみ違いは出ませんが、三角形と四角形の長さが希望の値になりません。ただし、オブジェクトの傾き角度は正しい値が算出されました(円の傾き角度は??)。

最後に結果を下表にまとめます。findContoursまとめ160830 どのような特徴量を求めるかにもよりますが、私が今回求めたかった特徴量をピンク色で囲みました。まだまだ、知らないことがありそうで、いろいろ遊べそうです
スポンサーサイト



OpenCV 3.1で輪郭検出処理(findContours)を使う(1)

 前回お話ししたラベリングを用いて解析する際に、当然のごとく問題になるのは、図のような傾いたオブジェクトの正確な長さ検出です。オブジェクト2、3は斜めに傾いており、ラベリング関数(connectedComponentsWithStats)の機能を駆使しても正確な径を測定することができませんでした。ラベリング結果160828
 そこで、今回はオブジェクトの輪郭を検出するfindContours関数を利用して、トライしました。まずは、結果画像から。findContours結果160828 ラベリング時とオブジェクトの検出順は異なりましたが、全検出できました。作成したコードは以下の通りです。

//輪郭検出処理
void ImageProc::fc() {

std::vector<std::vector<Point>> contours; //輪郭データ
int fontFace = FONT_HERSHEY_SCRIPT_SIMPLEX;
double fontScale = 0.5;

//輪郭検出
findContours(workimage[setimagenumber], contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
DetectObjNo = contours.size(); //検出オブジェクト数

Mat cimage = Mat::zeros(workimage[setimagenumber].size(), CV_8UC3); //結果画像初期化

for (int i = 0; i < contours.size(); i++)
{
Mat inputpoints;
Mat(contours[i]).convertTo(inputpoints, CV_32F);

RotatedRect box = minAreaRect(inputpoints); //最小矩形(回転を考慮)算出
RotatedRect box1 = fitEllipse(inputpoints); //楕円フィッティング

drawContours(cimage, contours, (int)i, Scalar::all(255), 1, 8); //結果画像(輪郭)描画

//結果代入
LabellingResd[i, 0] = box.center.x; //Cx(中心座標x)
LabellingResd[i, 1] = box.center.y; //Cy(中心座標y)
LabellingResd[i, 2] = box.size.width; //width
LabellingResd[i, 3] = box.size.height; //height
LabellingResd[i, 4] = contourArea(contours[i], false); //area 領域が囲む面積を算出
LabellingResd[i, 5] = box1.angle; //angle

//検出オブジェクトの囲み
Point2f vtx[4];
box.points(vtx);
for (int j = 0; j < 4; j++)
line(cimage, vtx[j], vtx[(j + 1) % 4], Scalar(0, 255, 0), 1, LINE_AA);

//中心座標(十字マーク)描画
contours_point[i, 0] = (int)box.center.x;
contours_point[i, 1] = (int)box.center.y;
line(cimage, Point(contours_point[i, 0], contours_point[i, 1] - 2), Point(contours_point[i, 0], contours_point[i, 1] + 2), Scalar(0, 255, 255), 1, 8, 0);
line(cimage, Point(contours_point[i, 0] - 2, contours_point[i, 1]), Point(contours_point[i, 0] + 2, contours_point[i, 1]), Scalar(0, 255, 255), 1, 8, 0);

//オブジェクト番号描画
char strtemp[10];
snprintf(strtemp, sizeof(strtemp), "%d", i+1);
cv::String labelstr = strtemp;
putText(cimage, labelstr, Point(contours_point[i, 0] + 5, contours_point[i, 1] + 5), fontFace, fontScale, Scalar(0, 255, 255), 1, 8);

}
workimage[processcounter] = cimage;//結果画像代入
}
輪郭検出処理のメインは9行目です。引数は以下の通りです。
workimage[setimagenumber] ... 解析する元画像(二値化画像)
contours ... 輪郭データ(点ベクトルで取得)
CV_RETR_EXTERNAL ... 輪郭抽出モード(最も外側の輪郭のみを抽出)
CV_CHAIN_APPROX_NONE ... 輪郭の近似手法(すべての輪郭点を完全に格納)

 輪郭検出後の処理は、19、20行目で「楕円フィッティング」と「最小矩形」の2種類行っています。面倒な感じもしますが、片方の処理のみではうまく行かないケースもありました。それについては、次回にお話しします。22行目で輪郭を白色で描画し、25~30行目で結果を別変数に代入しています。面積(Area)はcontourArea関数を、オブジェクトの傾き角度は「楕円フィッティング」のデータを用いています。33行目以降は、オブジェクトの緑色囲み、中心座標の十字マーク、オブジェクト番号の描画に関するものです。

 輪郭(findContours)の情報を用いれば、いろいろな特徴量を引き出すことができそうですね。市販の画像処理ライブラリ(MILやHALCON)は特徴量が簡単に引き出せ、目的のオブジェクトを抽出するのが非常に楽ですが、OpenCVでも似たような特徴量を引き出せそうですね。いろいろトライしてみたいと思います。

OpenCV 3.1でラベリングを使う(2)

 前回の続きです。前回詳しくお話しできなかった内容についてお話します。まずは、特徴量(面積)での検出オブジェクトの抽出と四角形の囲みについてです。


//特徴量で選択
void ImageProc::LabelSelect(int labelno, Mat statin, Mat centin) {

int k = 0;
array<int, 2>^ LabellingResTemp = gcnew array<int, 2>(10000, 6);
array<double, 2>^ LabellingCentTemp = gcnew array<double, 2>(10000, 2);

for (int i = 1; i <= labelno; i++) {
for (int j = 0; j <= 5; j++) {
LabellingResTemp[i, j] = statin.at<int>(i, j);
}
LabellingCentTemp[i, 0] = centin.at<double>(i, 0); //x
LabellingCentTemp[i, 1] = centin.at<double>(i, 1); //y

//areaで選別
if (LabellingResTemp[i, 4] > areaborder) {
k++;
for (int j = 0; j <= 5; j++) {
LabellingRes[k, j] = LabellingResTemp[i, j];
}
LabellingCent[k, 0] = LabellingCentTemp[i, 0];
LabellingCent[k, 1] = LabellingCentTemp[i, 1];
}
}

DetectObjNo = k;

//囲みと番号を付ける
for (int i = 1; i <= DetectObjNo; i++) {
char strtemp[10];
snprintf(strtemp, sizeof(strtemp), "%d", i);
cv::String labelstr = strtemp;

LabelBox(labelstr, LabellingRes[i, 0], LabellingRes[i, 1], LabellingRes[i, 2], LabellingRes[i, 3]);
}
}
 このコードでは、ラベリングで検出された全オブジェクトについて、面積で「再ふるい直し」をしています。ラベリングで求められた結果を引数として与え、16~23行目で面積しきい値areaborderより大きなオブジェクトを選んで、再カウントしています。29~35行目は、面積でふるわれたオブジェクトを四角で囲み、番号をつける部分です。LabelBox関数は自作関数で、以下のコードです。

//検出オブジェクトの囲み
void ImageProc::LabelBox(cv::String slabelno, int ileft, int itop, int iwidth, int iheight) {

rectangle(workimage[processcounter], Point(ileft, itop), Point(ileft + iwidth, itop + iheight), Scalar(0, 255, 255), 1, 8, 0);

int center_x = (int)((double)ileft + (double)(iwidth / 2)); //中心x
int center_y = (int)((double)itop + (double)(iheight / 2)); //中心y

line(workimage[processcounter], Point(center_x, center_y - 2), Point(center_x, center_y + 2), Scalar(0, 255, 255), 1, 8, 0);
line(workimage[processcounter], Point(center_x - 2, center_y), Point(center_x + 2, center_y), Scalar(0, 255, 255), 1, 8, 0);

int fontFace = FONT_HERSHEY_SCRIPT_SIMPLEX;
double fontScale = 0.5;
putText(workimage[processcounter], slabelno, Point(center_x + 5, center_y + 5), fontFace, fontScale, Scalar(0, 255, 255), 1, 8);

}
 ラベル番号と左上のx, y座標(Left, Top座標)とWidth、Heightのデータを引数として、4行目で四角形を描画しています。6, 7行目で四角形の中心座標(フェレ径の中心)を求め、9, 10行目でその位置に十字マークを入れています。最後に、14行目でラベル番号を文字記入しています。

 ここで、標準ラベリング関数を実行した際に出てくる重心座標、つまり、自作関数LabelSelectで出てくる重心座標(Gx, Gy) = (LabellingCentTemp[i, 0], LabellingCentTemp[i, 1])と、自作関数LabelBoxの中心座標(Cx, Cy)の違いを確認しておきます。
160821中心と重心 中心座標と異なり、重心座標は正しくオブジェクトの重心位置を示していることが確認できました。当たり前といえばそうかもしれませんが、念のための確認でした。

OpenCV 3.1でラベリングを使う(1)

 今回は、OpenCV 3.1でラベリング処理を行いました。ラベリング関数はOpenCV 3.0から標準で組み込まれていたのですが、実際に使ってみたのは今回が初めてです。
 OpenCV 2.4.xの時は、ラベリングをする際に、非常に苦労した(試行錯誤した)記憶があります。その時は、井村先生Labeling.hを使わせていただいたと思います(阪大から関学に移られて、昔のリンク先が変更になっているようです・・)。この他にも輪郭処理(cvFindContours)を用いた方法がいつもお世話になるこのサイトに紹介されていますが、簡便にできる方法ではなく、内容が非常に複雑です。

 OpenCV 3.0から組み込まれている「ラベリング」の関数は、connectedComponentsconnectedComponentsWithStatsの2つです。この関数についての詳しい使い方はこのサイトに、ラベリングそのものについては、このサイトに説明があります。

 今回は、connectedComponentsWithStatsを用いて遊んでみました。Labellingプログラムは、以下の通りで、自作のImageProc中に作成しました。サブルーチンを抜粋しました。

void ImageProc::Labelling(){

//ラベリング結果用
Mat labelImage(workimage[setimagenumber].size(), CV_32S); //結果画像
Mat statres; //Left, Top, Width, Height, Area, Max
Mat centroidsres; //重心座標

int nLabels = connectedComponentsWithStats(workimage[setimagenumber], labelImage, statres, centroidsres, 8, 4);

//ラベリング色分け用
std::vector<vec3b> colors(nLabels);
//背景は黒にする
colors[0] = Vec3b(0, 0, 0);
//ランダムに色を入れていく
for (int label = 1; label < nLabels; label++){
colors[label] = Vec3b((rand() & 255), (rand() & 255), (rand() & 255));
}

//ラベリング結果用
Mat dst(workimage[setimagenumber].size(), CV_8UC3);
//色をつけていく
for (int r = 0; r < dst.rows; r++) {
for (int c = 0; c < dst.cols; c++) {
int label = labelImage.at<int>(r, c);
Vec3b &pixel = dst.at<vec3b>(r, c);
pixel = colors[label];
}
}
workimage[processcounter] = dst;

//Label Select(特徴量選択)
LabelSelect(nLabels-1, statres, centroidsres); //背景ラベル分(-1)を引く
}

 8行目がラベリングを実行している命令です。戻り値nLabelsは検出されたラベルの個数です。また、引数は以下の通りです。

   ・ workimage[setimagenumber] ... ラベリングする画像。
   ・ labelImage ... ラベリングされた結果画像。
   ・ statres ... Left, Top, Width, Height, Area, Maxの結果が入ってくる。Maxは関数上では存在していますが、何の値なのかは意味不明。データ型はCV_32S(符号付き32ビット整数 int)。
   ・centroidsres ... 重心座標(フェレ径の中心座標ではない。検出オブジェクトの純粋な重心座標)データ型はCV_64F(倍精度実数浮動小数点数, 64ビット double )
   ・8 ... 8連結(8)か4連結(4)を選択。ここでは8連結を選択。
   ・4 ... 出力ファイルの型。CV_32S(=4: 符号付き32ビット整数 int)

 ラベリングされた結果画像labelImageはモノクロ画像なので、10~28行目で各検出オブジェクトに色を付けます。29行目は結果を表示用のバッファにコピーする命令です。

  ラベリングは通常、二値化画像に対して実行しますので、事前に準備しておきます。また、ラベリングはそもそも「粒子(ブロブ)解析」で粒子の個数をカウントしたり、粒子の「大きさ」や「特徴」を計測・判断したりする際によく用いますね。ラベリング後はいろいろな特徴量で仕分けをする機能が欲しくなります。

 そこで、今回は「面積」で仕分けしました。プログラムの32行目(自作のプログラム)で仕分けています。以下、実行結果です。生画像(640×480サイズ)と二値化画像(640×480サイズ)は以下の通りです。160821particle.png160821ThresholdImage.png

 面積(Area)しきい値200pixelsより小さいオブジェクトを除いて、抽出すると29個のオブジェクト検出できました。結果は、オブジェクトを四角形で囲んで、オブジェクト番号を付けました。また、数値結果はdataGridViewに表示させました。160821result.png dataGridViewのヘッダのAreaをクリックすると、データの並べ替えも可能です。これは便利です。Areaの大きな順に並べてくれました。
160821result2.png
 以上、長くなりましたので、今回お話しできなかった内容は次回にしたいと思います。

東山魁夷展に行く

 博多滞在も残りわずかになった8/14(日)に九博(九州国立博物館)に「東山魁夷 自然と人、そして町」を見に行きました。
東山魁夷チケット160814
 太宰府まで西鉄電車で行き、太宰府天満宮の参道の途中から曲がって、いざ博物館へ。

 美術・芸術に大変疎い私ですが、東山魁夷の名前は聞いたことがありました。風景画を描かれた日本画家です。芸術ド素人の私でも、絵の中の自然風景に引き込まれてしまいそうな力があり、展示を見終わった後でも、特徴的な群青色、緑色の残像が目に焼き付いてしまったほどでした。
 目玉は唐招提寺の全障壁画(襖絵)です。展示は和室(畳の部屋)の中を再現しており、見ごたえがありました。部屋の角(直角)をはさんで、風景画が連なっている構図で、本当に自分がその場にいるのではと錯覚しました。絵を見て、自分自身が、自然の中にいる気持ちになったのは、今回が初めてでした。
襖絵160814_1
襖絵160814_2
 太宰府に来ましたので、定番の梅ケ枝餅を「きくち」で買って帰宅しました。昔からのなじみの味で大変満足でした。これがまたうまいんです!

大アマゾン展に行く

 8/12(金)に福岡市博物館で開催されていた「大アマゾン展」を見に行きました。実家に帰省しても、自分自身の休養、ご先祖様の仏壇に手を合わせたり、年寄(両親)の話し相手になること以外は、何もすることがありませんので、毎度、博物館(福岡市博物館、九州国立博物館)に足を運びます。
大アマゾン展チケット160812
 大アマゾン展は、アマゾン川流域で生息する動物、昆虫等の展示がメインでした。ほとんどは国立科学博物館所有の動物剥製の展示でした。大変珍しい動物が、哺乳類、鳥類、爬虫類、両生類、魚類の順に並べられていました。個人的には、かわいらしい猿、カラフルな鳥、珍しい蝶などに魅かれました。写真撮影OKの展示だったので、興味のある動物の写真を撮りました。以下、その一部です。
amazon160812_1.png ゴールデンライオンタマリン。
amazon160812_2.png ナマケモノ。 
amazon160812_5.png カラフルなオウム。 
amazon160812_3.png タランチュラ。
amazon160812_4.png 透明な羽をもつ蝶。

 大変衝撃的だったのは、ヒバロ族の「干し首」でした。干し首とは、部族間の争いで首を切られた後に、後頭部を切って頭蓋骨を取り出したあとに縫合し、こぶし大のサイズにした首です。作り物のように見えましたが、本物でした。写真撮影NGにつき、リーフレットからのコピーです。
干し首160812

 アマゾンはもともとゴンドワナランドからアフリカ大陸やオーストラリア大陸などが分離した中の南アメリカ大陸にあり、各大陸の動物の祖先やその進化した動物が数多く生息しているとのこと。剥製の展示とはいえ、大変良い息抜きでした。

ネットを使えない環境で過ごす

 8/10(水)、会社が終わってから、実家の博多に帰省しました。今回も私と家族のスケジュールが合わず、一人だけの帰郷です。会社には決められた盆休み(夏休み)はなく、7~9月の3か月の間に3日間のみ休暇取得すれば良いのですが、すでに7月と8月前半に体調不良で休暇を取り、2日間分消費してしまいました(ありがたみのない楽しくない夏休みです・・・)。
 今回、残り1日分と有給休暇を1日使って、8/12, 8/15に休むことにしました。今年から8/11に「山の日」なる、ありがたい?祝日ができましたので、8/10夜~8/15昼の約5日間、博多で過ごせました。

 実家には私の両親(年寄二人)のみなので「ネット環境」がありません。また、私自身、ガラケー(ボタンの大きなお年寄り携帯:通話とメールのみ利用)とiPad mini(WiFi)ユーザなので、この実家での5日間は完全にネットワークから疎外された環境でした。
 それでも、こういう時(休みで時間が比較的ある時)に限って、調べたいことがメラメラと湧いてくるものです。結局、Webで確認したいこともあれば、買い物ついでにJR、西鉄、地下鉄の駅に足を延ばして、FreeのWiFi環境(Fukuoka-City Wi-Fi)でネットにつなぐという「ケチ臭い」5日間でした。

 それにしても、ネットが使えない環境は大変不便ですね。
実家にて、一緒に帰省したMacBook Airでプログラムを直していた時にも、ちょっとしたことを「検索」できません。非常に効率悪 !!です。ガラケーをスマートフォンに切り替えたら良いだけの話なのですが、日々の生活ではスマートフォンの必要性は感じていませんでした。費用対効果からも。会社と自宅との往復だけなので・・。
 今回、ネットを使えない環境で生活したことで、「ネット依存」になっている自分自身に気付くことができました。ネット環境がない所では、「本を読め」といった所でしょうか?安易に頭を使わずに何も考えない検索をしなくてもよく、「頭で考える」機会は増えそうな気がします(負け惜しみ・・)。
 
 実家から帰ってきて、いつもながらのネット環境に戻ってきました。悲しいかな、精神的にホッとしている自分がいます。複雑な今日この頃。

PWM制御でLEDの明るさを変える(2)

 前回の続きです。PWM制御の設定は、Raspberry PiのターミナルからwiringPiのgpioコマンドで行いました。

まず、PWMに対応したピン番号12(GPIO18)をpwmモードにします。
$ gpio -g mode 18 pwm

設定は0~1023の範囲で行い、例えば、1023を設定する場合は次の通りです。
$ gpio -g pwm 18 1023
1023より大きな値を設定しようとしても、1023が設定されるようです(実験結果から)。

電圧測定のプログラムは、以前のブログに記載した内容を参考にしました。1sec間隔で電圧を測定し、画面表示、ファイル保存するプログラムです。

// VoltMeasure.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wiringPi.h>
#include <wiringPiSPI.h>
#define SPI_CHANNEL 0

//SubString Command
int mysubstr( char *t, const char *s, int pos, int len )
{
if( pos < 0 || len < 0 || len > strlen(s) )
return -1;
for( s += pos; *s != '\0' && len > 0; len-- )
*t++ = *s++;
*t = '\0';
return 0;
}

//Main
int main(int argc, char **argv){
int retCode;
int i;

int a2dChannel0 = 0; // analog channel 0
int a2dChannel1 = 1; // analog channel 1
int a2dVal0 = 0; // 10bit 0-1023 (ch0)
int a2dVal1 = 0; // 10bit 0-1023 (ch1)
float a2dVol0 = 0.0; // analog voltage ch0
float a2dVol1 = 0.0; // analog voltage ch1
float Vref = 5.0; // Ref. voltage

FILE *fp;
char a[16]; // time(for file output)
char beforetime[3];
char nowtime[3];
time_t timer;

unsigned char data0[2];
unsigned char data1[2];

// SPI channel 0を1MHzで開始。
if (wiringPiSPISetup(SPI_CHANNEL, 1000000) < 0)
{
printf("SPISetup failed.\n");
}

time(&timer);

//initial time
mysubstr(beforetime,ctime(&timer),17,1);

//Loop
while(1){

time(&timer);
mysubstr(nowtime,ctime(&timer),18,1); //1secの位
//1secごとに測定・ファイル保存
if(strcmp(nowtime,beforetime) != 0){

strcpy(beforetime,nowtime);
mysubstr(a,ctime(&timer),11,8);

//Measure
//ch.0
data0[0] = 0b01100000 |( ((a2dChannel0 & 0x03) << 4)); // first byte transmitted -> start bit
data0[1] = 0; // third byte transmitted....don't care

retCode=wiringPiSPIDataRW (SPI_CHANNEL,data0,sizeof(data0));

a2dVal0 = (data0[0]<< 8) & 0b1100000000; //first 2 bit
a2dVal0 |= (data0[1] & 0xff);
a2dVol0 = (float)a2dVal0/1023 * Vref;

//ch.1
data1[0] = 0b01100000 |( ((a2dChannel1 & 0x03) << 4)); // first byte transmitted -> start bit
data1[1] = 0; // third byte transmitted....don't care

retCode=wiringPiSPIDataRW (SPI_CHANNEL,data1,sizeof(data1));

a2dVal1 = (data1[0]<< 8) & 0b1100000000; //first 2 bit
a2dVal1 |= (data1[1] & 0xff);
a2dVol1 = (float)a2dVal1/1023 * Vref;

//output
printf("Time: %s Volt0=%.3f[V] Volt1=%.3f[V]\n",a,a2dVol0,a2dVol1);

//fileoutput
fp = fopen("./mea.csv","a");
fprintf(fp,a);
fprintf(fp,",");
fprintf(fp,"%.3f",a2dVol0);
fprintf(fp,",");
fprintf(fp,"%.3f\n",a2dVol1);
fclose(fp);
sleep(1);
}
}
return 0;
}

 今回使用したCdSセル(GL5516)の照度と抵抗値の関係を仕様書から抜粋すると以下の通り。Lux-R_relation160806.png 一般的にCdSセルは照度と抵抗値が両対数グラフ上で直線になる特性を持っているようです。

 今回の実験で設定値(set)を0~1023まで変えた時の電圧VCdS、Vtotal-VCdS、電流 IとCdSの抵抗RCdSの値は下表の通りでした。result160806.png ここで、照度に該当するのはPWM制御の設定値と考えられます。設定値0~1023でLED照度の0~100%に相当すると考えて、両対数でプロットすると、見事なほどに仕様書と同じ直線関係が得られました。このことからPWM制御の設定値でLEDの照度が制御できていることがよく分かりました。

PWM制御でLEDの明るさを変える(1)

 以前のブログでRaspberry Piと東芝製のTA7291Pを用いてDCモータで遊んだことがありました。その時はTA7291Pの制御電源端子(4番ピン:Vref)に一定電圧をかけて一定速度でモータを正転/逆転させていました。

 今回、モータの速度を変えて遊ぼうかなと思い立ち、そういえばRaspberry PiでPWM(Pulse Width Modulation)制御ができることを思い出しました。使ったことがなかったので、早速モータの制御を行ってみました。ターミナルからコマンドを打ち込みながら、モータの回転速度を確認した所、確かに速度制御できているようです。ただし、Raspberry Pi(PWM)の設定に対し、どのような回転速度になっているのか、気になってしまいました。しかし、モータは設定値(範囲:0~1023)が低いと回転しない問題がありました。PWM設定の全範囲で評価したかったので、まずは簡単なLEDで明るさを変えて、設定と明るさの関係を調べてみようと思いました。

 LEDの明るさは照度計で測るべきなのかもしれませんが、今回は間接的にCdSセルを用いて評価しました。LEDとCdSセルの配置は以下の通りです。配置図160806配線したブレッドボードはアルミ箔で覆った小箱の中に入れて、その上から布を被せて外乱光が入らないようにしました。

 また、CdSセルの抵抗値を評価する上で、以下の回路を組みました。CdS_test160806.pngPWM制御を行うLEDは、240Ωの抵抗をかましてRaspberry Piの12番ピンにつなぎました。CdSセルは10kΩの抵抗と直列につなぎ、ACアダプタからDC 5Vをかけ、ADコンバータMCP3002でVtotalとVCdSを測定しました。RCdS_calc160806.pngこの回路を流れる電流をIとすると、
  I = (Vtotal - VCdS) / (10×1000)
で求めることができるので、CdSセルの抵抗RCdS
  RCdS = VCdS / I
で求めることができます。実験結果は、次回にお話しします。

ご訪問者数

(Since 24 July, 2016)

タグクラウド


プロフィール

Dr.BobT

Author: Dr.BobT
興味のおもむくままに生涯考え続けるエンジニアでありたい。

月別アーカイブ

メールフォーム

名前:
メール:
件名:
本文: