Google OS実験室 ~Moonlight 明日香~

GoogleのAndroidで遊び始めて, すでに6年以上が経った. Androidは思った以上の発展を遂げている. この技術を使って, 新しいことにチャレンジだ!!

画像処理

[OpenCV] 画像の一部のみを処理する

前回に続き, 画像処理の基本について説明する.

3.16 画像の一部のみを処理する[1][2]
ROI(Region Of Interest)を指定すると, 画像の一部を新たな画像のように扱うことができる.

[手順]
 (1) 画像データを読み込む.
 (2) ROIを指定して, 画像の一部を新たな画像とする.
 (3) ボックスフィルタを用いて画像を平滑化する.

[コード]
package com.moonlight_aska.android.opencv.image16;

import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.core.Size;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.widget.ImageView;

public class Image16Activity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        // cv::Mat src_img = cv::imread("../../iamge/lenna.png", 1);
        Mat srcMat = Highgui.imread("/sdcard/OpenCV/sample/lena.jpg", 1);
        if (!srcMat.empty()) {
         // cv::Mat dst_img = src_img.clone();
         Mat dstMat = srcMat.clone();
         // cv::Rect roi_rect(200, 200, 100, 100); // x, y, w, h
         Rect roiRect = new Rect(200, 200, 100, 100);
         // cv::Mat src_roi = src_img(roi_rect);
         // cv::Mat dst_roi = dst_img(roi_rect);

         Mat srcRoi = new Mat(srcMat, roiRect);
         Mat dstRoi = new Mat(dstMat, roiRect);

         
         // 何らかの処理...
         // cv::blur(src_roi, dst_roi, cv::Size(30, 30));

         Imgproc.blur(srcRoi, dstRoi, new Size(30, 30));
         
         Bitmap roiImg = convMatToBitmap(dstMat);
         ImageView roiView = (ImageView)findViewById(R.id.roi_view);
         roiView.setImageBitmap(roiImg);
        }
    }
   
    // MatからBitmapに変換
    Bitmap convMatToBitmap(Mat src) {
        Mat dst = new Mat();
        // BGR→RGBAに変換
        Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGR2RGBA, 4);
        Bitmap img = Bitmap.createBitmap(src.width(), src.height(), Bitmap.Config.ARGB_8888);
        // MatからBitmapに変換
        Utils.matToBitmap(dst, img);
        return img;
    }
}

[入力画像]
image02-1

[実行結果]
Image16

注) 例えば畳み込みなどで必要になる「ROIの外側の画素」は, 自動的に元の画像全体からのピクセルが利用されるらしい...

----
参照URL:
 [1] OpenCV 2 プログラミングブック OpenCV2.2/2.3対応
 [2] OpenCV逆引きリファレンス―OpenCV-CookBook

[OpenCV] 画像の一部を切り抜いて保存する

「3.14 画像のヒストグラムを計算・描画する」で少しつまっているので, 3.15を先に説明する.

3.15 画像の一部を切り抜いて保存する[1][2]
[手順]
 (1) 画像データを読み込む.
 (2) ROI(Region Of Interest)を指定して, 画像の一部を新たな画像とする.

[コード]
package com.moonlight_aska.android.opencv.image15;

import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.widget.ImageView;

public class Image15Activity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        // cv::Mat src_img = cv::imread("../../iamge/lenna.png", 1);
        Mat srcMat = Highgui.imread("/sdcard/OpenCV/sample/lena.jpg", 1);
        if (!srcMat.empty()) {
         // (x, y)=(200, 200), (width, height)=(100, 100)
         // cv::Mat roi_img(src_img, cv::Rect(200, 200, 100, 100));
         Mat roiMat = new Mat(srcMat, new Rect(200, 200, 100, 100));
         
         // cv::imwrite("lenna_clipped.png", roi_img);
         Highgui.imwrite("/sdcard/OpenCV/sample/lena_clipped.jpg", roiMat);
         Bitmap roiImg = convMatToBitmap(roiMat);
         ImageView roiView = (ImageView)findViewById(R.id.roi_view);
         roiView.setImageBitmap(roiImg);
        }
    }
   
    // MatからBitmapに変換
    Bitmap convMatToBitmap(Mat src) {
        Mat dst = new Mat();
        // BGR→RGBAに変換
        Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGR2RGBA, 4);
        Bitmap img = Bitmap.createBitmap(src.width(), src.height(), Bitmap.Config.ARGB_8888);
        // MatからBitmapに変換
        Utils.matToBitmap(dst, img);
        return img;
    }
}

[入力画像]
image02-1

[実行結果]
Image15

今回は, とても簡単でしたね.

----
参照URL:
 [1] OpenCV 2 プログラミングブック OpenCV2.2/2.3対応
 [2] OpenCV逆引きリファレンス―OpenCV-CookBook

[OpenCV] 楕円フィッティングを行う

前回に続き, 画像処理の基本について説明する.

3.13 楕円フィッティングを行う[1][2]

3.13.1 画像に対する楕円フィッティング
 画像から輪郭を抽出し, その輪郭に対して楕円フィッティングを行う.
[手順]
 (1) ここから"stuff.jpg"をPCに保存する.
 (2) 画像を480x360に縮小し, Android端末の/sdcard/OpenCV/sampleにコピーする.
 (3) 画像データを読み込む.
 (4) グレースケールに変換する.
 (5) 画像を二値化する.
 (6) 輪郭を検出する.
 (7) 楕円フィッテングする.
 (8) 楕円を描画する.

[コード]
package com.moonlight_aska.android.opencv.image13;

import java.util.ArrayList;
import java.util.List;

import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.RotatedRect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

import org.opencv.utils.Converters;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.widget.ImageView;

public class Image13Activity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // cv::Mat src_img = cv::imread("../../image/stuff.jpg", 1);
        Mat srcMat = Highgui.imread("/sdcard/OpenCV/sample/stuff480x360.jpg", 1);
        if (!srcMat.empty()) {
         // cv::Mat gry_img, bin_img;
         Mat grayMat = new Mat();
         Mat binMat = new Mat();

         // cv::cvtColor(src_img, work_img, CV_BGR2GRAY);
         Imgproc.cvtColor(srcMat, grayMat, Imgproc.COLOR_BGR2GRAY);
         
         // std::vector<std::vector<cv::Point> > contours;
         List<Mat> contours = new ArrayList<Mat>();
         // 画像の二値化
         // cv::threshold(gray_img, bin_img, 0, 255, cv::THRESH_BINARY|cv::THRESH_OTSU);

         Imgproc.threshold(grayMat, binMat, 0, 255, Imgproc.THRESH_BINARY|Imgproc.THRESH_OTSU);
         // 輪郭の抽出
         // cv::findContours(bin_img, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
         Mat hierarchy = new Mat();
         Imgproc.findContours(binMat, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_NONE);

         
         for (int i=0; i<contours.size(); ++i) {
          // size_t count = contours[i].size();
          Size count = contours.get(i).size();
          // if (count < 150 || count > 1000) continue; // (小さすぎる|大きすぎる) 輪郭を除外
          if (count.height < 150 || count.height > 1000) {
           continue;
          }

          //cv::Mat pointsf;
          Mat poMat = new Mat();
          // c::Mat(contours[i]).covertTo(pointsf, CV_32F);
          contours.get(i).convertTo(poMat, CvType.CV_32F);
          List<Point> pointsf = new ArrayList<Point>();
          Converters.Mat_to_vector_Point(poMat, pointsf);

          // 楕円フィッティング
          // cv::RotatedRect box = cv::fitEllipse(pointfs);
          RotatedRect box = Imgproc.fitEllipse(pointsf);
          // 楕円の描画
          // cv::ellipse(src_img, box, cv::Scalar(0, 0, 255), 2, CV_AA);

          Core.ellipse(srcMat, box, new Scalar(0, 0, 255), 2);
         }
         
         Bitmap srcImg = convMatToBitmap(srcMat, false);
         Bitmap binImg = convMatToBitmap(binMat, true);
         ImageView srcView = (ImageView)findViewById(R.id.ellipse_view);
         ImageView binView = (ImageView)findViewById(R.id.image_view);
         srcView.setImageBitmap(srcImg);
         binView.setImageBitmap(binImg);
        }
    }

    // MatからBitmapに変換
    private Bitmap convMatToBitmap(Mat src, boolean gray) {
     Mat dst = new Mat();
     // RGBAに変換
     if (gray) {
      Imgproc.cvtColor(src, dst, Imgproc.COLOR_GRAY2RGBA, 4);
     }
     else {
      Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGRA2RGBA, 4);     
     }
     Bitmap img = Bitmap.createBitmap(src.width(), src.height(), Bitmap.Config.ARGB_8888);
     // MatからBitmapに変換
     Utils.matToBitmap(dst, img);
     return img;
    }
}

[入力画像]
stuff480x360

[実行結果]
 上段:フィッティング結果
 下段:輪郭画像
image13

ここでのポイントは, Converters.Mat_to_vector_Pointメソッドを使って, MatからPointのリストに変換するとこかな!?
----
参照URL:
 [1] OpenCV 2 プログラミングブック OpenCV2.2/2.3対応
 [2] OpenCV逆引きリファレンス―OpenCV-CookBook

 

[OpenCV] 円を検出する


前回に続き, 画像処理の基本について説明する.

3.12 円を検出する[1][2]
 Hough変換を用い, 円を検出する.

[手順]
 (1) ここから"circles.png"を保存し, Android端末の/sdcard/OpenCV/sampleにコピーする.
 (2) 画像データを読み込む.
 (3) グレースケールに変換する.
 (4) Hough変換の前処理として, 画像の平滑化を行う.
 (5) Hough変換を用いて, 円を検出する.
 (6) 検出した円を描画する.

[コード]
package com.moonlight_aska.android.opencv.image12;

import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.widget.ImageView;

public class Image12Activity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        // cv::Mat src_img = cv::imread("../../image/circles.png", 1);
        Mat srcMat = Highgui.imread("/sdcard/OpenCV/sample/circles.png", 1);
        if (!srcMat.empty()) {
         // cv::Mat dst_img, work_img;
         Mat dstMat = new Mat();
         Mat workMat = new Mat();
         // dst_img = src_image.clone();
         dstMat = srcMat.clone();
         // cv::cvtColor(src_img, work_img, CV_BGR2GRAY);
         Imgproc.cvtColor(srcMat, workMat, Imgproc.COLOR_BGR2GRAY);
         
         // Hough変換のための前処理(画像の平滑化を行わないと誤検出が発生しやすい)
         // cv::GaussianBlur(work_img, work_img, cv::Size(11,11), 2, 2);

         Imgproc.GaussianBlur(workMat, workMat, new Size(11, 11), 2, 2);
         
         // Hough変換による円の検出と検出した円の描画
         // vector<cv::Vec3f> circles;

         Mat circlesMat = new Mat();
         // cv::HoughCircles(workMat, circles, CV_HOUGH_GRADIENT, 1, 100, 20, 50);
         Imgproc.HoughCircles(workMat, circlesMat, Imgproc.CV_HOUGH_GRADIENT, 1, 100, 20, 50);
         
         //std::vector<cv::Vec3f>::iterator it = circles.begin();
         float[] data = new float[3];
         // for ( ; it!=circles.end(); ++i) {
         for (int i=0; i<circlesMat.cols(); ++i) {
          // cv::Point center(cv::saturate_cast<int>((*it)[0]), cv::saturate_cast<int>((*it)[1]));
          circlesMat.get(0,  i, data);
          Point center = new Point(Math.round(data[0]), Math.round(data[1]));
          // int radius = cv::saturate_cast<int>((*it)[2]);
          int radius = Math.round(data[2]);
          // cv::circles(dst_img, center, radius, cv::Scalar(0, 0, 255), 2);
          Core.circle(dstMat, center, radius, new Scalar(0, 0, 255), 2);
         }
         
         Bitmap dstImg = convMatToBitmap(dstMat);
         ImageView dstView = (ImageView)findViewById(R.id.dst_view);
         dstView.setImageBitmap(dstImg);
        }
    }
   
    // MatからBitmapに変換
    private Bitmap convMatToBitmap(Mat src) {
     Mat dst = new Mat();
     // BGRA→RGBAに変換
     Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGRA2RGBA, 4);
     Bitmap img = Bitmap.createBitmap(src.width(), src.height(), Bitmap.Config.ARGB_8888);
     // MatからBitmapに変換
     Utils.matToBitmap(dst, img);
     return img;
    }
}

[入力画像]
circles


[実行結果]
image12

----
参照URL:
 [1] OpenCV 2 プログラミングブック OpenCV2.2/2.3対応
 [2] OpenCV逆引きリファレンス―OpenCV-CookBook


livedoor プロフィール
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

記事検索



  • ライブドアブログ