ドキュメントをトリミングするためのカムスキャナーのようなアプリケーションを作りたいです。
しかし、2つの画像と同じ機能が必要です..
最初の画像は、カメラでキャプチャされた画像を示しています..
2番目の画像は、このようにキャプチャされた画像部分を認識します..
私はますます研究していますが、結果が出ていないので、ここで尋ねます。
ありがとう
あなたの問題は、スキャンするオブジェクトを検出することだと思います。
パターン マッチングや特徴検出などのオブジェクト検出メカニズムでは、スキャンしているオブジェクトが正確に何であるかがわからないため、探している結果が得られません。
基本的には、画像内の長方形のオブジェクトを検索します。
これに対する基本的なアプローチは次のようになります。
画像に対してキャニー エッジ検出器を実行します。これを行う前に、画像を少しぼかすと役立つ場合があります。オブジェクトのエッジがはっきりと見えるはずです。
ここで、ハフ変換を実行して、画像内の線を見つけたいと考えています。
互いに角度が約 90 度の線を検索します。問題は、正しいものを見つけることです。おそらく、写真のフレームに最も近く、それらに適度に平行な線を使用するだけで十分です。
交点を見つけて、オブジェクトのエッジを定義します。
少なくとも、これにより、さらに調査する場所のヒントが得られるはずです。
このようなアプリのさらなるステップとして、ポイントの投影を計算し、オブジェクトのアフィン変換を行う必要があります。
これが役立つことを願っています。
これをすべて書いた後、私はこの投稿を見つけました。それはあなたを大いに助けるはずです。
私の回答は OpenCV を対象としているため、OpenCV ライブラリを使用する必要があります。これを行うには、Android Native Development Kit (NDK)をインストールする必要があります。OpenCV for Androidページには、Android で OpenCV を使用する方法に関する優れたチュートリアルがいくつかあります。
留意すべき点の 1 つは、Java ラッパーのほぼすべての関数がネイティブ メソッドを呼び出すことです。それには多くの時間がかかります。そのため、結果を Java 部分に返す前に、ネイティブ コードでできる限り多くのことを行う必要があります。
答えるには遅すぎることはわかっていますが、誰かの役に立つかもしれません。
次のコードを試してください。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
path = new Path();
path.moveTo(x1, y1); // this should set the start point right
//path.lineTo(x1, y1); <-- this line should be drawn at the end of course,sorry
path.lineTo(x2, y2);
path.lineTo(x3, y3);
path.lineTo(x4, y4);
path.lineTo(x1, y1);
canvas.drawPath(path, currentPaint);
}
このメソッドでイメージ マットを渡します。
void findSquares(Mat image, List<MatOfPoint> squares) {
int N = 10;
squares.clear();
Mat smallerImg = new Mat(new Size(image.width() / 2, image.height() / 2), image.type());
Mat gray = new Mat(image.size(), image.type());
Mat gray0 = new Mat(image.size(), CvType.CV_8U);
// down-scale and upscale the image to filter out the noise
Imgproc.pyrDown(image, smallerImg, smallerImg.size());
Imgproc.pyrUp(smallerImg, image, image.size());
// find squares in every color plane of the image
Outer:
for (int c = 0; c < 3; c++) {
extractChannel(image, gray, c);
// try several threshold levels
Inner:
for (int l = 1; l < N; l++) {
Imgproc.threshold(gray, gray0, (l + 1) * 255 / N, 255, Imgproc.THRESH_BINARY);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
// find contours and store them all as a list
Imgproc.findContours(gray0, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
MatOfPoint approx = new MatOfPoint();
// test each contour
for (int i = 0; i < contours.size(); i++) {
approx = approxPolyDP(contours.get(i), Imgproc.arcLength(new MatOfPoint2f(contours.get(i).toArray()), true) * 0.02, true);
// square contours should have 4 vertices after approximation
// relatively large area (to filter out noisy contours)
// and be convex.
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
double area = Imgproc.contourArea(approx);
if (area > 5000) {
if (approx.toArray().length == 4 &&
Math.abs(Imgproc.contourArea(approx)) > 1000 &&
Imgproc.isContourConvex(approx)) {
double maxCosine = 0;
Rect bitmap_rect = null;
for (int j = 2; j < 5; j++) {
// find the maximum cosine of the angle between joint edges
double cosine = Math.abs(angle(approx.toArray()[j % 4], approx.toArray()[j - 2], approx.toArray()[j - 1]));
maxCosine = Math.max(maxCosine, cosine);
bitmap_rect = new Rect(approx.toArray()[j % 4], approx.toArray()[j - 2]);
}
// if cosines of all angles are small
// (all angles are ~90 degree) then write quandrange
// vertices to resultant sequence
if (maxCosine < 0.3)
squares.add(approx);
}
}
}
}
}
}
この方法では、ドキュメントの 4 つのポイントを取得し、以下の方法を使用してこの画像を切り取ることができます。
public Bitmap warpDisplayImage(Mat inputMat) {
List<Point> newClockVisePoints = new ArrayList<>();
int resultWidth = inputMat.width();
int resultHeight = inputMat.height();
Mat startM = Converters.vector_Point2f_to_Mat(orderRectCorners(Previes method four poit list(like : List<Point> points)));
Point ocvPOut4 = new Point(0, 0);
Point ocvPOut1 = new Point(0, resultHeight);
Point ocvPOut2 = new Point(resultWidth, resultHeight);
Point ocvPOut3 = new Point(resultWidth, 0);
ocvPOut3 = new Point(0, 0);
ocvPOut4 = new Point(0, resultHeight);
ocvPOut1 = new Point(resultWidth, resultHeight);
ocvPOut2 = new Point(resultWidth, 0);
}
Mat outputMat = new Mat(resultWidth, resultHeight, CvType.CV_8UC4);
List<Point> dest = new ArrayList<Point>();
dest.add(ocvPOut3);
dest.add(ocvPOut2);
dest.add(ocvPOut1);
dest.add(ocvPOut4);
Mat endM = Converters.vector_Point2f_to_Mat(dest);
Mat perspectiveTransform = Imgproc.getPerspectiveTransform(startM, endM);
Imgproc.warpPerspective(inputMat, outputMat, perspectiveTransform, new Size(resultWidth, resultHeight), Imgproc.INTER_CUBIC);
Bitmap descBitmap = Bitmap.createBitmap(outputMat.cols(), outputMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(outputMat, descBitmap);
return descBitmap;
}