2012-07-31 114 views
1

我有一個足夠大的掃描儀,可以一次掃描多張圖片。 不幸的是,所有的圖片都存儲在一個jpg文件中,僅由 白色邊框分開。有什麼方法可以自動查找子圖像並將它們分別存儲在不同的文件中 ?我正在考慮使用OpenCV來完成這項工作,但是我找不到合適的功能 。有誰知道哪個OpenCV函數可以工作,或者有沒有其他方法(使用linux)?OpenCV查找子圖像

感謝, 康斯坦丁

+0

你可以做什麼樣的假設?所有的圖片矩形?他們總是出現在相同的地點嗎?最簡單的情況可能是具有完美的矩形,它總是出現在定義的網格內部,每個網格單元一個矩形。假設沒有矩形彎曲也會很好。是否有錯誤可接受?如果是這樣,它會留下額外的空白或拿走一些圖片? – Hammer 2012-08-01 00:01:26

+0

圖片或多或少都是旋轉的不同大小的矩形,它們並不總是出現在同一個位置,可以接受一些圖片的邊界像素的鬆動,以便它變成一個完美的矩形。背景不完全是白色的,但與圖像本身不同。 – 2012-08-01 17:03:36

+1

我之前沒有做過這個,所以拿着一粒鹽,但它聽起來像你想使用輪廓發現。首先,如果您可以對圖像進行閾值設置,使圖像全黑和背景全白,那麼這將是理想的選擇。根據你的工作情況,你可能需要模糊它。然後你可以找到輪廓並給他們包圍盒子。 OpenCV可以完成所有這些工作,請參閱教程[here](http://opencv.itseez.com/doc/tutorials/imgproc/table_of_content_imgproc/table_of_content_imgproc.html) – Hammer 2012-08-01 17:42:12

回答

0

我的快速和骯髒的解決方案,它與我的圖片的工作看起來是這樣的。我希望有類似問題的人可以用它作爲如何使用OpenCV的起點。

// g++ `pkg-config --cflags --libs opencv` parse.cp 

// include standard OpenCV headers, same as before 
#include <cv.h> 
#include <highgui.h> 
#include <stdio.h> 

// all the new API is put into "cv" namespace. Export its content 
using namespace cv; 
using namespace std; 

int main(int argc, char** argv) 
{ 
    string imagename = argc > 1 ? argv[1] : "lena.jpg"; 

    // the newer cvLoadImage alternative with MATLAB-style name 
    Mat imgf = imread("original/"+imagename); 

    if(!imgf.data) // check if the image has been loaded properly 
     return -1; 

    int border = 1000; 
    Mat img(imgf.rows+2*border,imgf.cols+2*border,CV_8UC3,Scalar(255,255,255)); 
    for (int i=0; i<imgf.cols; ++i) { 
     for (int j=0; j<imgf.rows; ++j) { 
      img.at<Vec3b>(j+border,i+border) = imgf.at<Vec3b>(j,i); 
     } 
    } 

    cout << "created border\n"; 
    Mat mask; 
    img.copyTo(mask); 

    Scalar diff(2,2,2); 
    floodFill(mask, Point(0,0), Scalar(0,0,255), NULL, diff, diff); 

    cout << "flood filled\n"; 

    imwrite("flood.png",mask); 

    for (int i=0; i<mask.cols; ++i) { 
     for (int j=0; j<mask.rows; ++j) { 
      if(mask.at<Vec3b>(j,i) != Vec3b(0,0,255)) { 
       mask.at<Vec3b>(j,i) = Vec3b(0,0,0); 
      } else { 
       mask.at<Vec3b>(j,i) = Vec3b(255,255,255); 
      } 
     } 
    } 

    cvtColor(mask, mask, CV_RGB2GRAY); 

    cout << "mask created\n"; 

    imwrite("binary.png",mask); 

    Mat sobelX; 
    Mat sobelY; 
    Mat sobel; 
    Sobel(mask,sobelX,CV_16S,1,0); 
    Sobel(mask,sobelY,CV_16S,0,1); 
    sobel = abs(sobelX)+abs(sobelY); 

    for (int i=0; i<mask.cols; ++i) { 
     for (int j=0; j<mask.rows; ++j) { 
      mask.at<char>(j,i) = abs(sobelX.at<short>(j,i))+abs(sobelY.at<short>(j,i)); 
     } 
    } 

    threshold(mask, mask, 127, 255, THRESH_BINARY); 

    cout << "sobel done\n"; 

    imwrite("sobel.png",mask); 

    vector<vector<Point> > contours; 
    vector<Vec4i> hierarchy; 

    findContours(mask, contours, hierarchy, 
     CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); 

    imwrite("contours.png",mask); 

    cout << "contours done\n"; 

    // iterate through all the top-level contours 
    int idx = 0; 
    for(; idx >= 0; idx = hierarchy[idx][0]) 
    { 
     RotatedRect box = minAreaRect(contours[idx]); 
     if(box.size.width > 100 && box.size.height > 100) { 
      Mat rot = getRotationMatrix2D(box.center,box.angle,1.0); 
      Mat rotimg; 
      warpAffine(img,rotimg,rot,Size(img.cols,img.rows)); 

      imwrite("rotimg.png",rotimg); 
      Mat subimg(box.size.width,box.size.height,CV_8UC3); 
      getRectSubPix(rotimg,box.size,box.center,subimg); 

      stringstream name; 
      name << "subimg_"<< imagename << "_" << idx << ".png"; 
      cout << name.str() << "\n"; 
      imwrite(name.str(),subimg); 
     } 
    } 

    imwrite("img.png",img); 
    imwrite("mask.png",mask); 

    cout << "Done\n"; 

    return 0; 
}