Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

This should extracts and straighten the small images

  1. Convert to gray scale
  2. Threshold
  3. Find Contours
  4. Get Bounding Rect and Rotated Rect
  5. Extracts the rect with mask for a default background
  6. straighten the small image

image description

image description image description image description and so on

Enjoy

void Main_ExtractStamps()
{
    Mat img,src, dst, gray, bw;
    img = imread("../img/stamp.png");
    //remove some unwanted cols on the left
    int colsToSkip = 80;
    src = img(Rect(colsToSkip, 0, img.cols - colsToSkip, img.rows));
    //keep a copy to show selection
    src.copyTo(dst);
    //convert to gray scale
    cvtColor(src, gray, CV_BGR2GRAY);
    threshold(gray, bw, 0, 255, THRESH_BINARY | THRESH_OTSU);
    // clear a bit
    Mat kernel = Mat::ones(Size(3,3), CV_8UC1);
    dilate(bw, bw, kernel);
    erode(bw, bw, kernel);
    Mat copyMask(bw.size(), bw.type());
    //detect outer contour of the stamps
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    vector<Rect>  stampsRect;
    vector<RotatedRect>  stampsRectRotated;
    findContours(bw, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    // iterate through all the top-level contours,
    int idx = 0;
    for (; idx >= 0; idx = hierarchy[idx][0])
    {
        //ignore small contour ... may be is noise 
        if (contours[idx].size() < 20) continue;
        //store contour boundingRect
        stampsRect.push_back(boundingRect(contours[idx]));
        stampsRectRotated.push_back(minAreaRect(contours[idx]));
        //prepare the copy mask 
        drawContours(copyMask, contours, idx, 255, FILLED, 8, hierarchy);
        //show selected contours 
        drawContours(dst, contours, idx, Scalar(0, 0, 255), 2, 8, hierarchy);
    }
    Mat rot_mat(2, 3, CV_32FC1);
    RotatedRect rr;
    for (idx = 0; idx < stampsRect.size(); idx++)
    {
        RotatedRect  rr = stampsRectRotated[idx];
        Rect rect = stampsRect[idx];
        Point center(rect.width / 2, rect.height / 2);
        //create an empty image with a default background
        Scalar bkg(0, 0, 0);
        Mat stamp(rect.height, rect.width, src.type(), bkg);
        //copy the stamp from source using a mask
        src(rect).copyTo(stamp, copyMask(rect));
        //straighten
        if (rr.angle != 0)
        {
            rot_mat=getRotationMatrix2D(center, 90+rr.angle, 1);
            warpAffine(stamp, stamp, rot_mat, stamp.size());
        }
        imwrite("../img/Stamp" + to_string(idx) + ".jpg", stamp);
        imshow("Stamp" + to_string(idx), stamp);
    }
    imshow("Bin", bw);
    imwrite("../img/StampDST..jpg", dst);
    imshow("DST", dst);
    waitKey();
}

This should extracts and straighten the small images

  1. Convert to gray scale
  2. Threshold
  3. Find Contours
  4. Get Bounding Rect and Rotated Rect
  5. Extracts the rect with mask for a default background
  6. straighten the small image

image description

image description image description image description and so on

If the contour isn't a rectangle however its the Bounding Rect will be extracted like this image description

Enjoy

void Main_ExtractStamps()
{
    Mat img,src, dst, gray, bw;
    img = imread("../img/stamp.png");
    //remove some unwanted cols on the left
    int colsToSkip = 80;
    src = img(Rect(colsToSkip, 0, img.cols - colsToSkip, img.rows));
    //keep a copy to show selection
    src.copyTo(dst);
    //convert to gray scale
    cvtColor(src, gray, CV_BGR2GRAY);
    threshold(gray, bw, 0, 255, THRESH_BINARY | THRESH_OTSU);
    // clear a bit
    Mat kernel = Mat::ones(Size(3,3), CV_8UC1);
    dilate(bw, bw, kernel);
    erode(bw, bw, kernel);
    Mat copyMask(bw.size(), bw.type());
    //detect outer contour of the stamps
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    vector<Rect>  stampsRect;
    vector<RotatedRect>  stampsRectRotated;
    findContours(bw, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    // iterate through all the top-level contours,
    int idx = 0;
    for (; idx >= 0; idx = hierarchy[idx][0])
    {
        //ignore small contour ... may be is noise 
        if (contours[idx].size() < 20) continue;
        //store contour boundingRect
        stampsRect.push_back(boundingRect(contours[idx]));
        stampsRectRotated.push_back(minAreaRect(contours[idx]));
        //prepare the copy mask 
        drawContours(copyMask, contours, idx, 255, FILLED, 8, hierarchy);
        //show selected contours 
        drawContours(dst, contours, idx, Scalar(0, 0, 255), 2, 8, hierarchy);
    }
    Mat rot_mat(2, 3, CV_32FC1);
    RotatedRect rr;
    for (idx = 0; idx < stampsRect.size(); idx++)
    {
        RotatedRect  rr = stampsRectRotated[idx];
        Rect rect = stampsRect[idx];
        Point center(rect.width / 2, rect.height / 2);
        //create an empty image with a default background
        Scalar bkg(0, 0, 0);
        Mat stamp(rect.height, rect.width, src.type(), bkg);
        //copy the stamp from source using a mask
        src(rect).copyTo(stamp, copyMask(rect));
        //straighten
        if (rr.angle != 0)
        {
            rot_mat=getRotationMatrix2D(center, 90+rr.angle, 1);
            warpAffine(stamp, stamp, rot_mat, stamp.size());
        }
        imwrite("../img/Stamp" + to_string(idx) + ".jpg", stamp);
        imshow("Stamp" + to_string(idx), stamp);
    }
    imshow("Bin", bw);
    imwrite("../img/StampDST..jpg", dst);
    imshow("DST", dst);
    waitKey();
}

This should extracts and straighten the small images

  1. Convert to gray scale
  2. Threshold
  3. Find Contours
  4. Get Bounding Rect and Rotated Rect
  5. Extracts the rect with mask for a default background
  6. straighten the small image

image description

image description image description image description and so on

If the contour isn't a rectangle however its the Bounding Rect will be extracted like this image description

EnjoyEDIT: Ok now you can play with trackbar to understand parameters

namespace ExtractStamps {
#define USE_COPY_MASK 0
int useEqualize, useNormalize, threshold, blurSize;
int extract;
Mat src, src_gray;
const std::string winName = "Extract Stamp";
void Main_ExtractStamps()
FindStamps(Mat &bw, Mat &dst)
{
    Mat img,src, dst, gray, bw;
    img = imread("../img/stamp.png");
    //remove some unwanted cols on // find external contours ignores holes in the left
    int colsToSkip = 80;
    src = img(Rect(colsToSkip, 0, img.cols - colsToSkip, img.rows));
    //keep a copy to show selection
    src.copyTo(dst);
    //convert to gray scale
    cvtColor(src, gray, CV_BGR2GRAY);
    threshold(gray, bw, 0, 255, THRESH_BINARY | THRESH_OTSU);
    // clear a bit
    Mat kernel = Mat::ones(Size(3,3), CV_8UC1);
    dilate(bw, bw, kernel);
    erode(bw, bw, kernel);
    Mat copyMask(bw.size(), bw.type());
    //detect outer contour of the stamps
    vector<vector<Point> fish
    vector<vector<cv::Point> > contours;
    vector<Vec4i> vector<cv::Vec4i> hierarchy;
    vector<Rect>  stampsRect;
    vector<RotatedRect>  stampsRectRotated;
    findContours(bw, cv::findContours(bw, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
    //draw all contours
    vector<Rect>  stampsRect;
    vector<RotatedRect>  stampsRectRotated;
#if USE_COPY_MASK==1
    Mat copyMask(bw.rows, bw.cols, bw.type(), Scalar(0));
#endif
    int minContourSize = cvRound(0.05*src.cols);
    for (int i = 0; i< contours.size(); i++) {
        Rect rect = boundingRect(contours[i]);
        if (rect.width < minContourSize) {
            if (rect.width > minContourSize / 2.0)
                // iterate through all the top-level contours,
    int idx = 0;
    for (; idx >= 0; idx = hierarchy[idx][0])
    {
        //ignore draw not so small contour ... may be is noise 
        if (contours[idx].size() < 20) contours in RED 
                drawContours(dst, contours, i, cv::Scalar(0, 0, 255), 1);
            continue;
        }
        // selected contours in GREEN
        drawContours(dst, contours, i, cv::Scalar(0, 255, 0), 1);
        //store contour boundingRect
        stampsRect.push_back(boundingRect(contours[idx]));
        stampsRectRotated.push_back(minAreaRect(contours[idx]));
        //prepare cv::rectangle(dst, rect, Scalar(255, 0, 0), 4); //draw it in BLUE
        stampsRect.push_back(rect);
        stampsRectRotated.push_back(minAreaRect(contours[i]));
#if USE_COPY_MASK==1
        // prepare the copy mask 
        drawContours(copyMask, //drawContours(copyMask, contours, idx, i, 255, FILLED, 8, hierarchy);
        //show selected contours 
        drawContours(dst, contours, idx, Scalar(0, 0, 255), 2, 8, hierarchy);
#endif
    }
    if (extract) {
        Mat rot_mat(2, 3, CV_32FC1);
     RotatedRect rr;
        double angle;
        for (idx (int i = 0; idx < i< stampsRect.size(); idx++)
    i++) {
         RotatedRect  rr = stampsRectRotated[idx];
stampsRectRotated[i];
            Rect rect = stampsRect[idx];
stampsRect[i];
            Point center(rect.width / 2, rect.height / 2);
        //create     // create an empty image with a default background
         Scalar bkg(0, 0, 255, 0);
         Mat stamp(rect.height, rect.width, src.type(), bkg);
        //copy the     // copy stamp from source 
#if USE_COPY_MASK==1
            // using a contour mask
         src(rect).copyTo(stamp, copyMask(rect));
#else
            src(rect).copyTo(stamp);
#endif
            //straighten
         if (rr.angle != 0) {
                if (rr.angle < 0)
                    angle = rr.angle;
                if (rr.angle < -45)
                    angle = 90 + rr.angle;
                if (abs(angle) > 0.5) {
            rot_mat=getRotationMatrix2D(center, 90+rr.angle,         rot_mat = getRotationMatrix2D(center, angle, 1);
             warpAffine(stamp, stamp, rot_mat, stamp.size());
stamp.size(), 1, 0, bkg);
                }
        imwrite("../img/Stamp"     }
            //imwrite("../img/Stamp" + to_string(idx) + ".jpg", stamp);
         imshow("Stamp" + to_string(idx), to_string(i), stamp);
     }
    imshow("Bin", }
}
void UseThreshold(const Mat &gray,Mat &bw)
{
    std::string win;

    // threshold to select bright
    cv::threshold(gray, bw, threshold, 255, cv::THRESH_BINARY);
    win = "threshold"; namedWindow(win, WINDOW_NORMAL);
    imshow(win, bw);
    imwrite("../img/StampDST..jpg", }
void Preprocessing(const Mat &imgIn, Mat &imgOut)
{
    if (blurSize >= 3) {
        blurSize += (1 - blurSize % 2);
        GaussianBlur(imgIn, imgOut, cv::Size(blurSize, blurSize), 0);
    }
    else
        imgIn.copyTo(imgOut);

    if (useEqualize)
        equalizeHist(imgOut, imgOut);
    if (useNormalize)
        normalize(imgOut, imgOut,0, 255, NORM_MINMAX);
    //BrightnessAndContrastAuto(img, img, 1);
}

void onTrackbar(int, void*)
{
    Mat tmp,bw, dst;

    Preprocessing(src_gray,tmp);
    UseThreshold(tmp,bw);

    src.copyTo(dst); // keep a copy to show the result
    FindStamps(bw, dst);
    imshow("DST", imshow(winName, dst);
    waitKey();
}

void Main()
{
    Mat img;
    //img = imread("../img/stamp-big.png");
    img = imread("../img/stamp-rot.png");
    // remove some unwanted cols and rows
    int skipRowTop = 0.01*img.rows;
    int skipRowBottom = 0.01*img.rows;
    int skipColLeft = 0.08*img.cols;
    int skipColRight = 0.01*img.cols;
    src = img.colRange(skipColLeft, img.cols - skipColRight).rowRange(skipRowTop, img.rows - skipRowBottom);
    namedWindow(winName, WINDOW_NORMAL);

    // convert to gray scale
    cvtColor(src, src_gray, CV_BGR2GRAY);

    // prepare defaults
    useEqualize = 0; useNormalize = 1;
    blurSize = 5; threshold = 70;
    extract = 0;

    createTrackbar("Equalize", winName, &useEqualize, 1, onTrackbar, 0);
    createTrackbar("Normalize", winName, &useNormalize, 1, onTrackbar, 0);
    createTrackbar("Blur Sigma", winName, &blurSize, 50, onTrackbar, 0);
    createTrackbar("Threshold", winName, &threshold, 255, onTrackbar, 0);
    createTrackbar("Extract", winName, &extract, 1, onTrackbar, 0);
    onTrackbar(0, 0);
    cv::waitKey(0);
}//main
}//namespace