アーカイブ
画像のだいたいの色を求める
カメラの入力画像から平均的な色を求めてRGBで出力する。
頻出色じゃなくて、全体的に赤っぽかったらr:200,g:50,b:50みたいなかんじで出す。赤っぽいとか青っぽいとかを求めたい。
数えて平均出そうかと思ったけどOpenCVで1×1ピクセルの画像にリサイズしてしまうのが速い&早いことに気づいた。
一応カメラのプレビューと、その色で塗りつぶしたウィンドウを出してみている。1ピクセルの画像はcvShowImageできないので、表示のために2ピクセルの画像を作っている
image1px.cpp
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
int main(int argc, char** argv) {
CvCapture *capture;
IplImage *img, *img1px, *imgR, *imgG, *imgB, *img2px;
img1px = cvCreateImage(cvSize(1,1), IPL_DEPTH_8U, 3);
imgR = cvCreateImage(cvSize(1,1), IPL_DEPTH_8U, 1);
imgG = cvCreateImage(cvSize(1,1), IPL_DEPTH_8U, 1);
imgB = cvCreateImage(cvSize(1,1), IPL_DEPTH_8U, 1);
img2px = cvCreateImage(cvSize(2,2), IPL_DEPTH_8U, 3);
char *winNameCapture = "Capture";
char *winName1px = "Image1px";
cvNamedWindow(winNameCapture, CV_WINDOW_AUTOSIZE);
cvNamedWindow(winName1px, CV_WINDOW_AUTOSIZE);
capture = cvCreateCameraCapture(0);
while (1) {
img = cvQueryFrame(capture);
cvShowImage(winNameCapture, img);
cvResize(img, img1px, CV_INTER_CUBIC);
cvSplit(img1px, imgB, imgG, imgR, NULL);
printf("r:%d, g:%d, b:%d\n",
(unsigned char)imgR->imageDataOrigin[0],
(unsigned char)imgG->imageDataOrigin[0],
(unsigned char)imgB->imageDataOrigin[0]);
cvResize(img1px, img2px, CV_INTER_CUBIC);
cvShowImage(winName1px, img2px);
if (cvWaitKey(33) == 'q') break;
}
cvReleaseCapture(&capture);
cvDestroyWindow(winNameCapture);
cvDestroyWindow(winName1px);
return 0;
}
Makefile
SRC = image1px.cpp
DST = image1px
prefix=/opt/local
CV_INCPATH=$(prefix)/include/opencv
CV_LIBPATH=$(prefix)/lib
CV_LIBS= -lcv -lcvaux -lcxcore -lhighgui
all:
g++ -O $(SRC) -o $(DST) -I$(CV_INCPATH) -L. -L$(CV_LIBPATH) $(CV_LIBS)
赤いポストイットをカメラの前に

出力
赤いことがわかる
r:186, g:61, b:61
r:186, g:61, b:61
r:191, g:63, b:61
r:198, g:67, b:63
r:200, g:69, b:63

白い。
r:149, g:146, b:147
r:159, g:155, b:156
r:169, g:156, b:159
r:169, g:160, b:161
r:169, g:159, b:161
r:169, g:159, b:161

赤黒いのかな?
r:126, g:92, b:124
r:126, g:92, b:124
r:126, g:92, b:124
r:126, g:92, b:124
r:126, g:92, b:124
r:126, g:92, b:124
r:125, g:92, b:124

白い
r:126, g:119, b:126
r:126, g:119, b:126
r:126, g:119, b:125
r:125, g:118, b:125
r:125, g:118, b:125
r:125, g:118, b:125
r:125, g:118, b:125
Cでgearman workerを書いてRubyのclientから呼び出す
gearmandをソースからインストールして、Cライブラリのlibgearmanが使えるようになった。
これでC言語でworkerを作ってRubyのclientから呼び出せる。環境はUbuntu9.04とgearmand0.11
■Cでworkerを書く
str_reverseというアビリティを持つworkerを作る。
ほぼAPIドキュメントのままだが、jobの引数を受け取るのと、値を返せるようにがんばった。ジョブ失敗した時とかのエラー処理全然書いてない。たぶんenum gearman_return_tを返せばいいんだろうけど
strreverse-worker.c
// 文字列をreverseして返すworker
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libgearman/gearman.h>
void *job_str_reverse(gearman_job_st *job, void *cb_arg, size_t *result_size,
gearman_return_t *ret_ptr)
{
char *str = (char *)gearman_job_workload(job);
int len = strlen(str);
printf("str:%s length:%d\n", str, len);
char reverse[len];
for(int i = 0; i < len; i++){
reverse[i] = str[len-i-1]; // 文字列を逆にする
}
char *result = strdup(reverse); // 結果の文字列はコピーしてポインタで返す
*result_size= gearman_job_workload_size(job);
*ret_ptr= GEARMAN_SUCCESS;
return result;
}
int main(int argc, char *argv[])
{
gearman_return_t ret;
gearman_worker_st worker;
gearman_worker_create(&worker);
gearman_worker_add_server(&worker, "127.0.0.1", 7003);
gearman_worker_add_function(&worker, "str_reverse", 0, job_str_reverse, NULL);
while(1) gearman_worker_work(&worker); // ジョブ登録したらループで待つ
gearman_worker_free(&worker);
return 0;
}
Makefile
# Linux用Makefilemakeするとstrreverse-workerができる。
SRC = strreverse-worker.c
DST = strreverse-worker
prefix=/usr/local
INCPATH=$(prefix)/include
LIBPATH=$(prefix)/lib
GEAR_LIBS=$(LIBPATH)/libgearman.a
all:
g++ -O $(SRC) -o $(DST) -I$(INCPATH)/libgearman -L. -L$(LIBPATH) $(GEAR_LIBS)
■Rubyでclientを書く
xing-gearman-serverを使うといい
client書く。実行時引数を一つずつstr_reverseに登録するclient。
strreverse-client.rb
#!/usr/bin/env ruby
require 'rubygems'
require 'gearman'
c = Gearman::Client.new(['localhost:7003'])
taskset = Gearman::TaskSet.new(c)
ARGV.each{|str|
puts "add task #{str}"
task = Gearman::Task.new('str_reverse', str)
task.on_complete{|result|
puts "return: #{str} => #{result}" # 文字列が逆になって返ってくる
}
taskset.add_task(task)
}
taskset.wait(100) # wait 100(sec)
■動かしてみる
worker動かす
./strreverse-worker
clientから3つ文字列登録
ruby strreverse-client.rb hello konitiwa asdfhujiko
すると文字列返ってくる
add task hello
add task konitiwa
return: hello => olleh
add task asdfhujiko
return: konitiwa => awitinok
return: asdfhujiko => okijuhfdsa
worker側の標準出力はこうなってた
str:hello length:5
str:konitiwa length:8
str:asdfhujiko length:10
workerを3つバックグラウンドで起動しておく
./strreverse-worker&
./strreverse-worker&
./strreverse-worker&
凄い勢いで処理されてるので非同期になってるのかよくわからない
ruby strreverse-client.rb hello konitiwa asdfhujiko aaiiaaiiaaii hogehogehogehoge mmmasdffajkl23rwdfv ahsdga9sd8uf9p8u nbjkasdoif98pu
add task hello
add task konitiwa
return: hello => olleh
add task asdfhujiko
return: konitiwa => awitinok
add task aaiiaaiiaaii
return: asdfhujiko => okijuhfdsa
add task hogehogehogehoge
return: aaiiaaiiaaii => iiaaiiaaiiaa
add task mmmasdffajkl23rwdfv
return: hogehogehogehoge => egohegohegohegoh
add task ahsdga9sd8uf9p8u
return: mmmasdffajkl23rwdfv => vfdwr32lkjaffdsammm
add task nbjkasdoif98pu
return: ahsdga9sd8uf9p8u => vfdu8p9fu8ds9agd
return: nbjkasdoif98pu => vfdu8up89fiods
PSoC Designer – CY8C29466の16bit Timer
CY3210-MiniEval基盤にCY8C29466マイコンを置いて、16ビットタイマーを4つ置いて動かした。
1秒毎?ぐらいで動かしてみたが、動いたは動いたけどまだ正確な仕組みがわからない。特にクロックの分周まわり。
ちなみに16bitタイマーはデジタルブロックを2つ消費するので、29466では同時に8個まで使える。
今回はPSoC CPU 基板 (ストロベリーリナックス社) – 趣味の電子工作研究工房 – 楽天ブログ(Blog)がとても参考になった。
■今回のコード
Source Code (PSoC Designer4.3 + C Compiler)
■タイマーの配置とクロック設定
Device EditorのUser Module Selection Viewから選択してくる。

PSoC Designer – CY8C29466で外部入力割り込み(C言語で)
前の記事s.h.log: PSoC Designer – CY8C29466でスイッチ入力と同じ動作を、割り込みでやってみた。
基盤も同じくCY3210-MiniEvalを使った。
動き方もまったく同じのを作っちゃったのでビデオは省略。ただスイッチの扱い方が違うだけ。
SourceCode (PSoC Designer 4.3 + C Compiler)
■動作設定
Device EditorのInterconnect Viewで

基本的にs.h.log: PSoC Designer – CY8C29466でスイッチ入力と同じだが、
タクトスイッチの接続されているPORT2-4のInterruptをFailingEdgeにする。
割り込みの仕方は3種類あり、
・FailingEdge → 立下り割り込み
・RisingEdge → 立ち上がり割り込み
・ChangeFromRead → 両エッジ変化割り込み
から選ぶ。
AVRのSIG_INTERRUPT0、SIG_INTERRUPT1はそれぞれINT0, INT1ピンの状態が変化を監視する外部入力割り込みだが、
PSoCの外部入力割込みはAVRのSIG_PIN_CHANGEの方と同じく、どのピンに変化があっても割り込みが発生してしまう。
だから、複数のピンの割り込みを有効にする場合は実際にどのピンの変化が割り込みを発生させたのか?をいちいち確認しなければならない。今回はマスクレジスタで1つのピン(PORT2-4)だけをenableにしているので必要ないけど。
軽くまとめると、PSoCの割り込みの設定は
・マスクレジスタで「どのピンの変化を監視するか」を指定
・ピン毎に「立ち上がり/下がり/両方の、どの条件で割り込むか」を指定
できる。でもこれはPSoC Designerが自動生成してくれるので下手に触る必要は無い。
マスクで複数enableに指定した場合は、実際にどのピンが反応したか?はプログラミングでなんとかする。(1回前のPRTnDRの状態をglobal変数に保存しておいて比較するとか)
この辺ははじめてのPSoCマイコンの「入出力&割り込みのしくみとスイッチ&LEDを使った実験」p.67に詳しく書かれている。

CY8C29466のGPIOでLEDピコピコさせた
「LEDをピコピコさせる」というのは横一列に並べたLEDをマイコンのピンから順番に電流を出したり出さなかったりして順番に点灯させる事を指す。
GPIOの開閉、代入、wait処理、for文if文、インクリメントなどのマイコンプログラミングでよく使う要素が入っているので、新しいマイコンを使う時はこれをやってみる事にしている。
ちなみにGPIOへの入力は、チャタリングやプルアップなど色々あるので別にやる。
→LED ピコピコ 検索結果
あと最近知ったけど GPIO はGeneral-Purpose I/Oの略で、つまり汎用ピンの事なんだね。
PSoC MiniProg付属のPSoCMiniEvalにCY8C29466を載せてやってみた。
Source Code(PSoC Designer 4.3 + C Compiler)
動かした。
今回も桑野さんのはじめてのPSoCマイコンのp.63-72「入出力&割り込みのしくみとスイッチ&LEDを使った実験」を参考にした。

最近のコメント