Ask Your Question
1

Search small images on one images.

asked 2016-02-02 09:54:37 -0600

Restomix gravatar image

updated 2016-02-05 14:14:49 -0600

I have a picture in which there are small pictures. They are separated by black background.Further I save this small pictures.Please help me i am new in OpenCV.I know that I have to find edges.How then me divided small pictures? Give an example or literature.I work c#/c++.Thank you very much.Image:image descriptionC:\fakepath\1.pngC:\fakepath\test222.png

edit retag flag offensive close merge delete

Comments

How your small images are arranged on the big one ? like a grid or random ? have small images same size, or same height (width) or each image has its size ? and orientation ? could you give us a sample ?

pklab gravatar imagepklab ( 2016-02-02 10:23:46 -0600 )edit

Random. Example added on top.

Restomix gravatar imageRestomix ( 2016-02-02 10:38:23 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
4

answered 2016-02-02 13:43:31 -0600

pklab gravatar image

updated 2016-02-09 05:44:18 -0600

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

EDIT: 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 FindStamps(Mat &bw, Mat &dst)
{
    // find external contours ignores holes in the fish
    vector<vector<cv::Point> > contours;
    vector<cv::Vec4i> hierarchy;
    cv::findContours(bw, contours, hierarchy, 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)
                // draw not so small 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
        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, contours, i, 255, FILLED, 8, hierarchy);
#endif
    }
    if (extract) {
        Mat rot_mat(2, 3, CV_32FC1);
        RotatedRect rr;
        double angle;
        for (int i = 0; i< stampsRect.size(); i++) {
            RotatedRect  rr = stampsRectRotated[i];
            Rect rect = stampsRect[i];
            Point center(rect.width / 2, rect.height / 2);
            // create an empty image with a default background
            Scalar bkg(0, 255, 0);
            Mat stamp(rect.height, rect.width, src.type(), bkg);
            // 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, angle, 1);
                    warpAffine(stamp, stamp, rot_mat, stamp.size(), 1, 0, bkg);
                }
            }
            //imwrite("../img/Stamp" + to_string(idx) + ".jpg", stamp);
            imshow("Stamp" + to_string(i), stamp);
        }
    }
}
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);
}
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(winName, dst);
}

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 ...
(more)
edit flag offensive delete link more

Comments

very very thank you). If picture is not in the form of a square?How then cut small image?

Restomix gravatar imageRestomix ( 2016-02-03 11:44:34 -0600 )edit

see stamp 10c... you could try the code yourself to test more cases or use it as base for your work . if you like the answer you could mark it as accepted

pklab gravatar imagepklab ( 2016-02-03 12:51:33 -0600 )edit

Thank you again, I understand.

Restomix gravatar imageRestomix ( 2016-02-03 13:20:28 -0600 )edit

This algorithm does not work for http://answers.opencv.org/upfiles/145... reason?and for .jpg.Help me please, I will be very grateful to you.

Restomix gravatar imageRestomix ( 2016-02-05 14:20:01 -0600 )edit

I found the reason is the image quality(pixels) of the image.

// clear a bit
Mat kernel = Mat::ones(Size(3,3), CV_8UC1);//3,3 need change
//ignore small contour ... may be is noise 
    if (contours[idx].size() < 20) continue;//20 need change

How to choose an option, depending on the image quality?Thank you in advance.
Restomix gravatar imageRestomix ( 2016-02-05 15:56:13 -0600 )edit

My code could be a base for your project but not the solution :). The idea is: use a threshold to separate foreground (the stamp) from the dark background. The 2nd image has a lot of noise because of 8bit color. If you can't improve the image, you should use some filter like Gaussian or median blur. You should also define small contour size related to image size... something like minContourSize > img.cols *0.1, same for colsToSkip. At the end you could try some other approach like this

pklab gravatar imagepklab ( 2016-02-08 11:13:32 -0600 )edit

Thank you very much you are very good person. Sorry for importunity(will not be repeated). I will work with your algorithm, he best for me.I am exporting images from PDF.Maybe I export a different look for the best option.

Restomix gravatar imageRestomix ( 2016-02-08 13:32:28 -0600 )edit

@Restomix look at the new code. It uses some preprocessing and trackbars to play around parameters. It works for 2nd image too.

pklab gravatar imagepklab ( 2016-02-09 05:46:40 -0600 )edit

Beautiful code.Thank you again)

Restomix gravatar imageRestomix ( 2016-02-10 11:25:52 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2016-02-02 09:54:37 -0600

Seen: 1,013 times

Last updated: Feb 09 '16