तकनीक का मूल मैं नीचे साझा कर रहा हूं cv::HoughLinesP()
का उपयोग ग्रेस्केल छवि में रेखा खंडों को खोजने के लिए करता है।
एप्लिकेशन इनपुट छवि को ग्रेस्केल के रूप में लोड करके शुरू होता है। तो यह एक बुनियादी पूर्व प्रसंस्करण कार्रवाई निष्पादित छवि की कुछ विशेषताओं को बढ़ाने के लिए, पता लगाने cv::HoughLinesP()
द्वारा किया जाता में सुधार करने का लक्ष्य:
#include <cv.h>
#include <highgui.h>
#include <algorithm>
// Custom sort method adapted from: http://stackoverflow.com/a/328959/176769
// This is used later by std::sort()
struct sort_by_y_coord
{
bool operator()(cv::Vec4i const& a, cv::Vec4i const& b) const
{
if (a[1] < b[1]) return true;
if (a[1] > b[1]) return false;
return false;
}
};
int main()
{
/* Load input image as grayscale */
cv::Mat src = cv::imread("13531682.jpg", 0);
/* Pre-process the image to enhance the characteristics we are interested at */
medianBlur(src, src, 5);
int erosion_size = 2;
cv::Mat element = cv::getStructuringElement(cv::MORPH_CROSS,
cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1),
cv::Point(erosion_size, erosion_size));
cv::erode(src, src, element);
cv::dilate(src, src, element);
/* Identify all the lines in the image */
cv::Size size = src.size();
std::vector<cv::Vec4i> total_lines;
cv::HoughLinesP(src, total_lines, 1, CV_PI/180, 100, size.width/2.f, 20);
int n_lines = total_lines.size();
std::cout << "* Total lines: "<< n_lines << std::endl;
cv::Mat disp_lines(size, CV_8UC1, cv::Scalar(0, 0, 0));
// For debugging purposes, the block below writes all the lines into disp_lines
// for (unsigned i = 0; i < n_lines; ++i)
// {
// cv::line(disp_lines,
// cv::Point(total_lines[i][0], total_lines[i][2]),
// cv::Point(total_lines[i][3], total_lines[i][4]),
// cv::Scalar(255, 0 ,0));
// }
// cv::imwrite("total_lines.png", disp_lines);
सभी रेखा खंडों का पता चला दृश्य के लिए एक फाइल करने के लिए लिखा जा सकता है इस बिंदु पर, प्रयोजनों:
इस बिंदु हम लाइनों के बारे में हमारी वेक्टर सॉर्ट करने के लिए है क्योंकि cv::HoughLinesP()
कि ऐसा नहीं करता है की जरूरत है, और हम वेक्टर लाइनों के समूहों की पहचान करने के लिए, को मापने और तुलना द्वारा सक्षम होने के लिए हल कर की जरूरत है रेखाओं के बीच दूरी:
/* Sort lines according to their Y coordinate.
The line closest to Y == 0 is at the first position of the vector.
*/
sort(total_lines.begin(), total_lines.end(), sort_by_y_coord());
/* Separate them according to their (visible) groups */
// Figure out the number of groups by distance between lines
std::vector<int> idx_of_groups; // stores the index position where a new group starts
idx_of_groups.push_back(0); // the first line indicates the start of the first group
// The loop jumps over the first line, since it was already added as a group
int y_dist = 35; // the next groups are identified by a minimum of 35 pixels of distance
for (unsigned i = 1; i < n_lines; i++)
{
if ((total_lines[i][5] - total_lines[i-1][6]) >= y_dist)
{
// current index marks the position of a new group
idx_of_groups.push_back(i);
std::cout << "* New group located at line #"<< i << std::endl;
}
}
int n_groups = idx_of_groups.size();
std::cout << "* Total groups identified: "<< n_groups << std::endl;
कोड ऊपर बस एक नया vector<int>
में लाइनों के वेक्टर के सूचकांक पदों संग्रहीत करता है के अंतिम भाग इसलिए हम जानते हैं जो लाइनों एक नया समूह शुरू होता है।
उदाहरण के लिए, मान लें कि नए वेक्टर में संग्रहीत इंडेक्स हैं: 0 4 8 12
। याद रखें: वे प्रत्येक समूह के को परिभाषित करते हैं। इसका मतलब है कि समूहों की समाप्ति रेखाएं हैं: 0, 4-1, 4, 8-1, 8, 12-1, 12
।
यह जानते हुए कि, हम निम्नलिखित कोड लिखें:
/* Mark the beginning and end of each group */
for (unsigned i = 0; i < n_groups; i++)
{
// To do this, we discard the X coordinates of the 2 points from the line,
// so we can draw a line from X=0 to X=size.width
// beginning
cv::line(disp_lines,
cv::Point(0, total_lines[ idx_of_groups[i] ][7]),
cv::Point(size.width, total_lines[ idx_of_groups[i] ][8]),
cv::Scalar(255, 0 ,0));
// end
if (i != n_groups-1)
{
cv::line(disp_lines,
cv::Point(0, total_lines[ idx_of_groups[i+1]-1 ][9]),
cv::Point(size.width, total_lines[ idx_of_groups[i+1]-1 ][10]),
cv::Scalar(255, 0 ,0));
}
}
// mark the end position of the last group (not done by the loop above)
cv::line(disp_lines,
cv::Point(0, total_lines[n_lines-1][11]),
cv::Point(size.width, total_lines[n_lines-1][12]),
cv::Scalar(255, 0 ,0));
/* Save the output image and display it on the screen */
cv::imwrite("groups.png", disp_lines);
cv::imshow("groove", disp_lines);
cv::waitKey(0);
cv::destroyWindow("groove");
return 0;
}
और जिसके परिणामस्वरूप छवि है:
यह एक सटीक मिलान नहीं है, लेकिन यह करीब है। यहां और वहां कुछ बदलावों के साथ यह दृष्टिकोण बहुत बेहतर हो सकता है।मैं sort_by_y_coord
के लिए एक स्मार्ट तर्क लिखकर शुरू करूंगा, जो एक्स कोऑर्डिनेट्स (यानी छोटे रेखा सेगमेंट) के बीच छोटी दूरी वाली रेखाओं को त्यागना चाहिए, और ऐसी रेखाएं जो एक्स अक्ष पर पूरी तरह से गठबंधन नहीं हैं (जैसे दूसरे समूह में से एक आउटपुट छवि में)। एप्लिकेशन द्वारा उत्पन्न पहली छवि का मूल्यांकन करने के लिए समय निकालने के बाद यह सुझाव अधिक समझ में आता है।
शुभकामनाएं।
शायद आप एक नमूना छवि शामिल कर सकते हैं? –
स्टैक ओवरफ्लो में आपका स्वागत है। कृपया मेरे उत्तर की सावधानीपूर्वक समीक्षा करें, फिर अगर यह आपकी मदद करता है तो इसे वोट दें। आप इसे अपने प्रश्न के आधिकारिक उत्तर के रूप में चुनने के लिए इसके पास स्थित चेकबॉक्स पर क्लिक कर सकते हैं। इस सामान को करके आप इस थ्रेड को व्यवस्थित करके अपने और हमारे जैसे भविष्य के आगंतुकों की सहायता करेंगे। – karlphillip