exStickとOpenCV

技術紹介

ちまたには,OpenCVを使って○○しましたというWeb上の記事がたくさんありますね.楽しそうだなあと横目に見る日々を過ごしていたのですが,2015年の締めくくりにexStickとOpenCVで遊んでみる事にしました.

実験環境

実験環境はexStickとOV7670です.exStickのFPGAには,100MbpsのネットワークをつかってVGA画像をPCに送り続ける簡単なハードウェアが実装されています.

extick_ov7670

OpenCVと組み合わせて画像処理

これまでは,「UDPで送られてくるデータを組み立てて動画像として表示する」という簡単なフロントエンドを実装していました.今回は,一歩すすんで,受信したデータをOpenCVのイメージデータとして表示,処理するというのを試してみました.

結果は次のように.順に,”そのまま表示”,”グレースケール化”,”エッジ検出”,”人の顔抽出”です.パソコンの処理性能ってすごいですね.

1db208175ec7e53f52cdb52eb2fa27ce 9769512ddd016f23c0d484695551e548 8ae0b14f985f5c44e190ac82014c5003 2b02f007d71697ffd6e7cd69796f7bd8

 

ソースコード

ソースコードはこんな感じ.opencv_client.cxx

メインの部分は次の通りです.UDPパケットを組み立てるところ以外は,よくあるOpenCVのサンプルです.顔検出用のデータはOpenCV 2.11に同梱のものを使いました.本当に便利ですね.

今回は手抜き実装で,画像の受信と処理を逐次に行なっているため,取りこぼしは発生するのですが,目をつぶることにします.それでも,カメラの前で手を振ってみてもそう違和感はありませんでした.

    for(;;){
      
      for(int i = 0; i < 480; i++){
        numrcv = recv(sock, buf, 2048, 0);
        int y = toInt(buf, 0);
        for(int j = 0; j < 640 * 2; j++){
          raw[y * 640 * 2 + j] = buf[j + 4];
        }
      }
      
      int r, g, b, y0, y1, cb, cr;
      for(int i = 0; i < 320; i++){
        for(int j = 0; j < 480; j++){
          y0 = ((int)raw[j*640*2+4*i+0]) & 0x000000FF;
          cb = ((int)raw[j*640*2+4*i+1]) & 0x000000FF;
          y1 = ((int)raw[j*640*2+4*i+2]) & 0x000000FF;
          cr = ((int)raw[j*640*2+4*i+3]) & 0x000000FF;
          
          r = (int)(y0                        + 1.40200 * (cr - 128));
          g = (int)(y0 - 0.34414 * (cb - 128) - 0.71414 * (cr - 128));
          b = (int)(y0 + 1.77200 * (cb - 128));
          
          r = r < 0 ? 0 : r; r = r > 255 ? 255 : r;
          g = g < 0 ? 0 : g; g = g > 255 ? 255 : g;
          b = b < 0 ? 0 : b; b = b > 255 ? 255 : b;
          
          rgb[3*((2*i)+640*j)+0] = b;
          rgb[3*((2*i)+640*j)+1] = g;
          rgb[3*((2*i)+640*j)+2] = r;
          
          r = (int)(y1                        + 1.40200 * (cr - 128));
          g = (int)(y1 - 0.34414 * (cb - 128) - 0.71414 * (cr - 128));
          b = (int)(y1 + 1.77200 * (cb - 128));
          
          r = r < 0 ? 0 : r; r = r > 255 ? 255 : r;
          g = g < 0 ? 0 : g; g = g > 255 ? 255 : g;
          b = b < 0 ? 0 : b; b = b > 255 ? 255 : b;
          rgb[3*((2*i+1)+640*j)+0] = b;
          rgb[3*((2*i+1)+640*j)+1] = g;
          rgb[3*((2*i+1)+640*j)+2] = r;
        }
      }

      cv::Mat image = cv::Mat(Size(640, 480), CV_8UC3, rgb);
      cv::imshow("Receive", image);

      cv::Mat gray_image;
      cv::cvtColor(image, gray_image, CV_BGR2GRAY, 0);
      cv::imshow("Gray", gray_image);

      cv::Mat sobel_x, sobel_y, sobel;
      Sobel(gray_image, sobel_x, CV_32F, 1, 0);
      Sobel(gray_image, sobel_y, CV_32F, 0, 1);
      sobel = (abs(sobel_x) + abs(sobel_y)) / 2.0;
      cv::threshold(sobel, sobel, 100, 255, THRESH_BINARY_INV);
      cv::imshow("Sobel", sobel);

      faces.clear();
      cascade.detectMultiScale(image, faces, 1.1, 2, 0, Size(4, 4));
      for (int i = 0; i < faces.size(); i++){
        rectangle(image,
                  Point(faces[i].x,faces[i].y),
                  Point(faces[i].x + faces[i].width,faces[i].y + faces[i].height),
                  Scalar(0, 200, 0),
                  3,
                  CV_AA);
      }
      cv::imshow("Face", image);
      
      cvWaitKey(10);

    }

まとめ?

やってみましたー,という話で特にまとめというものはないのですが,exStickから受信した動画像をOpenCVを使ってオンタイムで処理するのは,なかなか楽しいものです.次のステップとしては,一部のHW化とか,活用事例とか考えてみたいなと思っています.

コメント

タイトルとURLをコピーしました