OpenCV 實現圖片的水平投影與垂直投影,並進行行分割

來源:互聯網
上載者:User

OpenCV 實現圖片的水平投影與垂直投影,並進行行分割

對於印刷體圖片來說,進行水平投影和垂直投影可以很快的進行分割,本文就在OpenCV中如何進行水平投影和垂直投影通過代碼進行說明。

水平投影:二維映像在y軸上的投影

垂直投影:二維映像在x軸上的投影

由於投影的映像需要進行二值化,本文採用積分二值化的方式,對圖片進行處理。

具體代碼如下:

//積分二值化
void thresholdIntegral (Mat inputMat, Mat& outputMat)
{

    int nRows = inputMat.rows;
    int nCols = inputMat.cols;

    // create the integral image
    Mat sumMat;
    integral (inputMat, sumMat);

    int S = MAX (nRows, nCols) / 8;
    double T = 0.15;

    // perform thresholding
    int s2 = S / 2;
    int x1, y1, x2, y2, count, sum;

    int* p_y1, *p_y2;
    uchar* p_inputMat, *p_outputMat;

    for (int i = 0; i < nRows; ++i)
    {
        y1 = i - s2;
        y2 = i + s2;

        if (y1 < 0)
        {
            y1 = 0;
        }
        if (y2 >= nRows)
        {
            y2 = nRows - 1;
        }

        p_y1 = sumMat.ptr<int> (y1);
        p_y2 = sumMat.ptr<int> (y2);
        p_inputMat = inputMat.ptr<uchar> (i);
        p_outputMat = outputMat.ptr<uchar> (i);

        for (int j = 0; j < nCols; ++j)
        {
            // set the SxS region
            x1 = j - s2;
            x2 = j + s2;

            if (x1 < 0)
            {
                x1 = 0;
            }
            if (x2 >= nCols)
            {
                x2 = nCols - 1;
            }

            count = (x2 - x1)* (y2 - y1);

            // I(x,y)=s(x2,y2)-s(x1,y2)-s(x2,y1)+s(x1,x1)
            sum = p_y2[x2] - p_y1[x2] - p_y2[x1] + p_y1[x1];

            if ((int) (p_inputMat[j] * count) < (int) (sum* (1.0 - T)))
            {
                p_outputMat[j] = 0;
            }
            else
            {
                p_outputMat[j] = 255;
            }
        }
    }
}
//垂直方向投影
void picshadowx (Mat binary)
{
    Mat paintx (binary.size(), CV_8UC1, Scalar (255)); //建立一個全白圖片,用作顯示

    int* blackcout = new int[binary.cols];
    memset (blackcout, 0, binary.cols * 4);

    for (int i = 0; i < binary.rows; i++)
    {
        for (int j = 0; j < binary.cols; j++)
        {
            if (binary.at<uchar> (i, j) == 0)
            {
                blackcout[j]++; //垂直投影按列在x軸進行投影
            }
        }
    }
    for (int i = 0; i < binary.cols; i++)
    {
        for (int j = 0; j < blackcout[i]; j++)
        {
            paintx.at<uchar> (binary.rows-1-j, i) = 0; //翻轉到下面,便於觀看
        }
    }
    delete blackcout;
    imshow ("paintx", paintx);

}
//水平方向投影並行分割
void picshadowy (Mat binary)

  //是否為白色或者黑色根據二值映像的處理得來
    Mat painty (binary.size(), CV_8UC1, Scalar (255)); //初始化為全白
 
  //水平投影
  int* pointcount = new int[binary.rows]; //在二值圖片中記錄行中特徵點的個數
    memset (pointcount, 0, binary.rows * 4);//注意這裡需要進行初始化

    for (int i = 0; i < binary.rows; i++)
    {
        for (int j = 0; j < binary.cols; j++)
        {
            if (binary.at<uchar> (i, j) == 0)
            {
                pointcount[i]++; //記錄每行中黑色點的個數 //水平投影按行在y軸上的投影
            }
        }
    }

    for (int i = 0; i < binary.rows; i++)
    {
        for (int j = 0; j < pointcount[i]; j++) //根據每行中黑色點的個數,進行迴圈
        {
           
            painty.at<uchar> (i, j) = 0;
        }

    }

    imshow ("painty", painty);

    vector<Mat> result;
    int startindex = 0;
    int endindex = 0;
    bool inblock = false; //是否遍曆到字元位置

    for (int i = 0; i < painty.rows; i++)
    {
     
        if (!inblock&&pointcount[i] != 0) //進入有字元地區
        {
            inblock = true;
            startindex = i;
            cout << "startindex:" << startindex << endl;
        }
        if (inblock&&pointcount[i] == 0) //進入空白區
        {
            endindex = i;
            inblock = false;
            Mat roi = binary.rowRange (startindex, endindex+1); //從而記錄從開始到結束行的位置,即可進行行切分
            result.push_back (roi);
        }
    }

    for (int i = 0; i < result.size(); i++)
    {
        Mat tmp = result[i];
        imshow ("test"+to_string (i), tmp);
    }
    delete pointcount;

}
int main (int argc, char* argv[])
{
 
      Mat src = cv::imread ("test.jpg");

        if (src.empty())
        {
            cerr << "Problem loading image!!!" << endl;
            return -1;
        }

        imshow("in",src);
     
        Mat gray;

        if (src.channels() == 3)
        {
            cv::cvtColor (src, gray, CV_BGR2GRAY);     
        }
        else
        {
            gray = src;
        }
   

        Mat bw2 = Mat::zeros (gray.size(), CV_8UC1);
        thresholdIntegral (gray, bw2);

        cv::imshow ("binary integral", bw2);
 
        //picshadowx (bw2);
        picshadowy (bw2);
        waitKey (0);
   
    return 0;
}

輸入圖片:

二值圖片:

 

水平投影:

 

垂直投影:

 

行切割:

 該處理方法,對印刷體有較好的效果,因為印刷體的行列區分明顯,因此可以很快的進行行與列的分割。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.