web-dev-qa-db-ja.com

国民IDカードの検出と詳細の取得

以下のタイプの国民IDを検出して詳細を取得しようとしています。たとえば、署名の場所は人物画像の右上隅、この場合は「BC」で見つける必要があります。

enter image description here

IPhoneでこのアプリケーションを実行する必要があります。 Opencvを使用することを考えましたが、どのようにしてマークされた詳細を達成できますか?同様の種類のカードを使用してアプリケーションをトレーニングする必要がありますか、OCRが役立ちますか?

モバイルアプリケーションに特定の実装はありますか?

また、クレジットカードの詳細を検出するcard-ioを使用しましたが、Card-ioは他のカードの詳細も検出しますか?

更新:

テキスト検出に tesseract を使用しました。 Tesseractは、画像にテキストのみがある場合に有効です。そのため、赤いマークの付いた領域を切り取り、Tesseractへの入力として指定すると、MRZパーツでうまく機能します。

Tesseractには IOS実装 があり、これでテストしました。

私は何をする必要がありますか?

今、テキスト検出部分を自動化しようとしています。現在、次の項目を自動化する予定です。

1)顔のトリミング(Viola-jones顔検出器の使用を完了しました)。

2)この例の「BC」のイニシャルを写真から取得する必要があります。

3)IDカードからMRZ領域を抽出/検出します。

私は2と3をやろうとしていますが、どんなアイデアやコードスニペットも素晴らしいでしょう。

21
2vision2

これらのIDが特定の幅、高さ、オフセット、間隔などを持つ標準テンプレートに従って準備されていると仮定すると、テンプレートベースのアプローチを試すことができます。

MRZは簡単に検出できます。画像でそれを検出したら、テンプレート内のMRZをそれにマッピングする変換を見つけます。この変換がわかったら、テンプレート上の任意の領域(個人の写真など)を画像にマッピングし、その領域を抽出できます。

以下は、幸せな道をたどる非常に簡単なプログラムです。一般にMRZを特定するには、さらに処理を行う必要があります(たとえば、遠近法の歪みや回転がある場合)。画像を測定するだけでテンプレートを作成しましたが、あなたの場合はうまくいきません。アイデアを伝えたかっただけです。画像は wiki から取得されました

    Mat rgb = imread(INPUT_FILE);
    Mat gray;
    cvtColor(rgb, gray, CV_BGR2GRAY);

    Mat grad;
    Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
    morphologyEx(gray, grad, MORPH_GRADIENT, morphKernel);

    Mat bw;
    threshold(grad, bw, 0.0, 255.0, THRESH_BINARY | THRESH_OTSU);

    // connect horizontally oriented regions
    Mat connected;
    morphKernel = getStructuringElement(MORPH_RECT, Size(9, 1));
    morphologyEx(bw, connected, MORPH_CLOSE, morphKernel);

    // find contours
    Mat mask = Mat::zeros(bw.size(), CV_8UC1);
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(connected, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    vector<Rect> mrz;
    double r = 0;
    // filter contours
    for(int idx = 0; idx >= 0; idx = hierarchy[idx][0])
    {
        Rect rect = boundingRect(contours[idx]);
        r = rect.height ? (double)(rect.width/rect.height) : 0;
        if ((rect.width > connected.cols * .7) && /* filter from rect width */
            (r > 25) && /* filter from width:hight ratio */
            (r < 36) /* filter from width:hight ratio */
            )
        {
            mrz.Push_back(rect);
            rectangle(rgb, rect, Scalar(0, 255, 0), 1);
        }
        else
        {
            rectangle(rgb, rect, Scalar(0, 0, 255), 1);
        }
    }
    if (2 == mrz.size())
    {
        // just assume we have found the two data strips in MRZ and combine them
        CvRect max = cvMaxRect(&(CvRect)mrz[0], &(CvRect)mrz[1]);
        rectangle(rgb, max, Scalar(255, 0, 0), 2);  // draw the MRZ

        vector<Point2f> mrzSrc;
        vector<Point2f> mrzDst;

        // MRZ region in our image
        mrzDst.Push_back(Point2f((float)max.x, (float)max.y));
        mrzDst.Push_back(Point2f((float)(max.x+max.width), (float)max.y));
        mrzDst.Push_back(Point2f((float)(max.x+max.width), (float)(max.y+max.height)));
        mrzDst.Push_back(Point2f((float)max.x, (float)(max.y+max.height)));

        // MRZ in our template
        mrzSrc.Push_back(Point2f(0.23f, 9.3f));
        mrzSrc.Push_back(Point2f(18.0f, 9.3f));
        mrzSrc.Push_back(Point2f(18.0f, 10.9f));
        mrzSrc.Push_back(Point2f(0.23f, 10.9f));

        // find the transformation
        Mat t = getPerspectiveTransform(mrzSrc, mrzDst);

        // photo region in our template
        vector<Point2f> photoSrc;
        photoSrc.Push_back(Point2f(0.0f, 0.0f));
        photoSrc.Push_back(Point2f(5.66f, 0.0f));
        photoSrc.Push_back(Point2f(5.66f, 7.16f));
        photoSrc.Push_back(Point2f(0.0f, 7.16f));

        // surname region in our template
        vector<Point2f> surnameSrc;
        surnameSrc.Push_back(Point2f(6.4f, 0.7f));
        surnameSrc.Push_back(Point2f(8.96f, 0.7f));
        surnameSrc.Push_back(Point2f(8.96f, 1.2f));
        surnameSrc.Push_back(Point2f(6.4f, 1.2f));

        vector<Point2f> photoDst(4);
        vector<Point2f> surnameDst(4);

        // map the regions from our template to image
        perspectiveTransform(photoSrc, photoDst, t);
        perspectiveTransform(surnameSrc, surnameDst, t);
        // draw the mapped regions
        for (int i = 0; i < 4; i++)
        {
            line(rgb, photoDst[i], photoDst[(i+1)%4], Scalar(0,128,255), 2);
        }
        for (int i = 0; i < 4; i++)
        {
            line(rgb, surnameDst[i], surnameDst[(i+1)%4], Scalar(0,128,255), 2);
        }
    }

結果:写真と姓の領域がオレンジ色になります。青色のMRZ。 enter image description here

21
dhanushka

Card.ioは、エンボスクレジットカード専用に設計されています。このユースケースでは機能しません。

3
tomwhipple

現在、この目的で使用できるPassportEyeライブラリがあります。それは完璧ではありませんが、私の経験では非常にうまく機能しています: https://pypi.python.org/pypi/PassportEye/

2
user1747134