This should extracts and straighten the small images
- Convert to gray scale
- Threshold
- Find Contours
- Get Bounding Rect and Rotated Rect
- Extracts the rect with mask for a default background
- straighten the small image
and so on
If the contour isn't a rectangle however its the Bounding Rect will be extracted like this
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)
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 ?
Random. Example added on top.