Tôi đang tìm một thuật toán để cắt bớt các đoạn đường ngắn từ đầu ra của máy dò cạnh. Như có thể thấy trong hình ảnh (và liên kết) bên dưới, có một số cạnh nhỏ được phát hiện không phải là các dòng "dài". Lý tưởng nhất là tôi chỉ muốn 4 mặt của tứ giác xuất hiện sau khi xử lý, nhưng nếu có một vài dòng đi lạc, nó sẽ không phải là một vấn đề lớn ... Bất cứ đề nghị?Cắt tỉa các đoạn đường ngắn từ đầu ra của đầu dò cạnh?
Trả lời
Trước khi tìm ra mép trước quá trình hình ảnh với một mở hoặc gần hoạt động (hoặc cả hai), có nghĩa là, xói mòn Tiếp theo giãn ra, hoặc giãn ra Tiếp theo xói mòn. điều này sẽ loại bỏ các đối tượng nhỏ hơn nhưng để lại những vật thể lớn hơn gần như nhau.
Tôi đã tìm kiếm các ví dụ trực tuyến và tốt nhất tôi có thể tìm thấy ở trang 41 của this PDF.
Nhìn vào hình ảnh ví dụ. Đường viền cạnh của hình chữ nhật chỉ mỏng 1 pixel! Nếu bạn xói mòn đầu tiên, bạn sẽ hoàn toàn mất hình chữ nhật cũng như các cạnh nhỏ. Nếu bạn làm giãn trước, bạn có thể đóng vài khoảng trống trong hình chữ nhật lớn của mình, nhưng đó là một vấn đề khác, và không thực sự giúp bạn loại bỏ các cạnh nhỏ. –
@Levy - Không, như tôi đã nêu rõ trong câu trả lời của tôi, hình ảnh phải được đóng TRƯỚC KHI TÌM KIẾM EDGES.Tất nhiên điều này không nên được áp dụng cho các cạnh (nhưng đối với các đối tượng từ đó các cạnh được tính toán). – tom10
@ tom10 - cảm ơn lời khuyên, tôi chuyển sang một hoạt động mở (thay thế một bộ lọc Gaussian) và tôi nhận được đầu ra phát hiện cạnh Canny tốt hơn nhiều (kết quả hoạt động gần trong hiệu suất tốt hơn). Tôi đã nghĩ về việc sử dụng xói mòn/giãn nở, nhưng tôi đã nghĩ đến việc sử dụng sau khi phát hiện cạnh, mà không làm việc với các đường mỏng. – user21293
tôi nghi ngờ rằng điều này có thể được thực hiện với một hoạt động địa phương đơn giản. Nhìn vào hình chữ nhật bạn muốn giữ - có một số khoảng trống, do đó thực hiện một hoạt động cục bộ để loại bỏ các đoạn đường ngắn có thể sẽ làm giảm đáng kể chất lượng của đầu ra mong muốn.
Do đó tôi sẽ cố gắng phát hiện hình chữ nhật là nội dung quan trọng bằng cách đóng các khoảng trống, lắp đa giác hoặc thứ gì đó tương tự, và sau đó trong bước thứ hai sẽ loại bỏ nội dung không quan trọng còn lại. Có thể là Hough transform có thể hữu ích.
CẬP NHẬT
tôi chỉ sử dụng sample application này sử dụng một Kernel Hough transform với hình ảnh mẫu của bạn và có bốn dây chuyền đẹp phù hợp hình chữ nhật của bạn.
+1 để đề xuất biến đổi Hough. Chỉ cần tìm bốn đỉnh mạnh nhất trong không gian biến đổi, và đó là tứ giác của bạn. – erickson
Biến đổi Hough có thể là một hoạt động rất tốn kém.
Một thay thế có thể làm việc tốt trong trường hợp của bạn như sau:
chạy 2 hoạt động hình thái toán học gọi là một hình ảnh gần gũi (http://homepages.inf.ed.ac.uk/rbf/HIPR2/close.htm) với một đường ngang và dọc (có chiều dài được xác định từ thử nghiệm) phần tử cấu trúc tương ứng. Điểm này là để đóng tất cả các khoảng trống trong hình chữ nhật lớn.
chạy phân tích thành phần được kết nối. Nếu bạn đã thực hiện hình thái một cách hiệu quả, hình chữ nhật lớn sẽ xuất hiện dưới dạng một thành phần được kết nối. Sau đó nó chỉ tiếp tục lặp qua tất cả các thành phần được kết nối và chọn ra ứng cử viên có khả năng nhất nên là hình chữ nhật lớn.
Đây là cách tôi sẽ làm. Nếu mục tiêu là tìm vị trí của hình chữ nhật lớn, hãy chọn thành phần lớn nhất. Nếu mục tiêu chỉ là để loại bỏ các cạnh ngắn (tiếng ồn) sau đó loại bỏ tất cả các thành phần đủ nhỏ, hoặc tất cả, nhưng lớn nhất. –
Có lẽ việc tìm kiếm các thành phần kết nối, sau đó loại bỏ các thành phần có ít hơn X pixel (theo kinh nghiệm quyết tâm), tiếp theo là sự giãn nở dọc theo các đường ngang/dọc để kết nối lại những khoảng trống trong hình chữ nhật
Có thể thực hiện theo hai kỹ thuật chính:
Thao tác dựa trên vector: ánh xạ các hòn đảo pixel của bạn thành các cụm (blob, voronoi khu, bất kỳ). Sau đó áp dụng một số chẩn đoán để sửa chữa các phân đoạn, như thuật toán xấp xỉ chuỗi Teh-Chin, và thực hiện cắt tỉa của bạn khi các phần tử vectơ (bắt đầu, điểm cuối, chiều dài, hướng và vv).
Đặt hoạt động dựa trên: cụm dữ liệu của bạn (như trên). Đối với mỗi cụm, tính toán các thành phần chính và phát hiện đường từ vòng tròn hoặc bất kỳ hình dạng nào khác bằng cách tìm các cụm chỉ hiển thị 1 giá trị riêng (hoặc 2 nếu bạn tìm phân đoạn "béo", có thể giống với dấu ba chấm). Kiểm tra các eigenvectors liên kết với các giá trị riêng để có thông tin về định hướng của các đốm màu và thực hiện lựa chọn của bạn.
Cả hai cách có thể dễ dàng được khám phá với OpenCV (trước đây thực sự thuộc danh mục thuật toán "Đường phân tích").
Trong trường hợp ai đó thực hiện bước này, OpenCV 2.x sẽ đưa ra một ví dụ có tên là squares.cpp về cơ bản sẽ làm móng tay tác vụ này.
tôi đã thực hiện một sửa đổi nhỏ để các ứng dụng để cải thiện việc phát hiện các tứ giác
Mã:
#include "highgui.h"
#include "cv.h"
#include <iostream>
#include <math.h>
#include <string.h>
using namespace cv;
using namespace std;
void help()
{
cout <<
"\nA program using pyramid scaling, Canny, contours, contour simpification and\n"
"memory storage (it's got it all folks) to find\n"
"squares in a list of images pic1-6.png\n"
"Returns sequence of squares detected on the image.\n"
"the sequence is stored in the specified memory storage\n"
"Call:\n"
"./squares\n"
"Using OpenCV version %s\n" << CV_VERSION << "\n" << endl;
}
int thresh = 70, N = 2;
const char* wndname = "Square Detection Demonized";
// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
double angle(Point pt1, Point pt2, Point pt0)
{
double dx1 = pt1.x - pt0.x;
double dy1 = pt1.y - pt0.y;
double dx2 = pt2.x - pt0.x;
double dy2 = pt2.y - pt0.y;
return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}
// returns sequence of squares detected on the image.
// the sequence is stored in the specified memory storage
void findSquares(const Mat& image, vector<vector<Point> >& squares)
{
squares.clear();
Mat pyr, timg, gray0(image.size(), CV_8U), gray;
// karlphillip: dilate the image so this technique can detect the white square,
Mat out(image);
dilate(out, out, Mat(), Point(-1,-1));
// then blur it so that the ocean/sea become one big segment to avoid detecting them as 2 big squares.
medianBlur(out, out, 3);
// down-scale and upscale the image to filter out the noise
pyrDown(out, pyr, Size(out.cols/2, out.rows/2));
pyrUp(pyr, timg, out.size());
vector<vector<Point> > contours;
// find squares only in the first color plane
for(int c = 0; c < 1; c++) // was: c < 3
{
int ch[] = {c, 0};
mixChannels(&timg, 1, &gray0, 1, ch, 1);
// try several threshold levels
for(int l = 0; l < N; l++)
{
// hack: use Canny instead of zero threshold level.
// Canny helps to catch squares with gradient shading
if(l == 0)
{
// apply Canny. Take the upper threshold from slider
// and set the lower to 0 (which forces edges merging)
Canny(gray0, gray, 0, thresh, 5);
// dilate canny output to remove potential
// holes between edge segments
dilate(gray, gray, Mat(), Point(-1,-1));
}
else
{
// apply threshold if l!=0:
// tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
gray = gray0 >= (l+1)*255/N;
}
// find contours and store them all as a list
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
vector<Point> approx;
// test each contour
for(size_t i = 0; i < contours.size(); i++)
{
// approximate contour with accuracy proportional
// to the contour perimeter
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
// square contours should have 4 vertices after approximation
// relatively large area (to filter out noisy contours)
// and be convex.
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
if(approx.size() == 4 &&
fabs(contourArea(Mat(approx))) > 1000 &&
isContourConvex(Mat(approx)))
{
double maxCosine = 0;
for(int j = 2; j < 5; j++)
{
// find the maximum cosine of the angle between joint edges
double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
maxCosine = MAX(maxCosine, cosine);
}
// if cosines of all angles are small
// (all angles are ~90 degree) then write quandrange
// vertices to resultant sequence
if(maxCosine < 0.3)
squares.push_back(approx);
}
}
}
}
}
// the function draws all the squares in the image
void drawSquares(Mat& image, const vector<vector<Point> >& squares)
{
for(size_t i = 1; i < squares.size(); i++)
{
const Point* p = &squares[i][0];
int n = (int)squares[i].size();
polylines(image, &p, &n, 1, true, Scalar(0,255,0), 3, CV_AA);
}
imshow(wndname, image);
}
int main(int argc, char** argv)
{
if (argc < 2)
{
cout << "Usage: ./program <file>" << endl;
return -1;
}
static const char* names[] = { argv[1], 0 };
help();
namedWindow(wndname, 1);
vector<vector<Point> > squares;
for(int i = 0; names[i] != 0; i++)
{
Mat image = imread(names[i], 1);
if(image.empty())
{
cout << "Couldn't load " << names[i] << endl;
continue;
}
findSquares(image, squares);
drawSquares(image, squares);
imwrite("out.jpg", image);
int c = waitKey();
if((char)c == 27)
break;
}
return 0;
}
Dưới đây là một giải pháp lọc hình thái đơn giản sau các dòng của @ Tom10:
Giải pháp trong matlab:
se1 = strel('line',5,180); % linear horizontal structuring element
se2 = strel('line',5,90); % linear vertical structuring element
I = rgb2gray(imread('test.jpg'))>80; % threshold (since i had a grayscale version of the image)
Idil = imdilate(imdilate(I,se1),se2); % dilate contours so that they connect
Idil_area = bwareaopen(Idil,1200); % area filter them to remove the small components
Ý tưởng là về cơ bản kết nối các đường nét ngang để làm cho một bộ phận lớn và lọc bởi một bộ lọc mở khu vực sau này để có được những hình chữ nhật.
Kết quả:
- 1. Đầu ra của đường ống để cắt
- 2. Java RandomAccessFile cắt ngắn từ đầu
- 3. Cửa sổ đầu ra của IntelliJ IDEA cắt đầu ra
- 4. Đường cắt đoạn đường và đoạn
- 5. Đầu vào/đầu ra nhanh trong lập trình cạnh tranh
- 6. đầu ra đường ống của quy trình con.Chọn các tệp
- 7. Đầu ra của chương trình đường ống đến ít hơn không hiển thị đầu ra của
- 8. Có một đoạn cắt ngắn để quay lại phần đầu của tệp bằng trình chỉnh sửa vi không?
- 9. Mở một luồng tập tin đầu ra nhị phân mà không cắt ngắn
- 10. Cắt tỉa tự động rpart?
- 11. Cách cắt nhiều cột từ nhiều tệp và in đầu ra thành các tệp khác nhau
- 12. Có thể cắt bớt đầu ra khi xem nội dung của các khung dữ liệu không?
- 13. php: cắt thẻ br từ đầu chuỗi?
- 14. Xuất sang PNG từ Adobe Illustrator cắt các cạnh
- 15. Làm cách nào để cắt các đường được đọc từ đầu vào chuẩn trên bash?
- 16. Đường ray cắt ngắn bằng nút chuyển 'đọc thêm'
- 17. Trích xuất đường bao đơn từ các cạnh của Canny
- 18. Python - đầu ra từ các hàm?
- 19. SSIS - Đầu ra lỗi nguồn (Không có hàng nào được gửi tới (các) đầu ra lỗi ....)
- 20. Làm thế nào để ngăn chặn vòng lặp while của Bash từ khoảng trắng cắt tỉa?
- 21. Bàn cắt ngắn với bảng điều khiển đường ray
- 22. Đầu ra của lệnh đường ống, nhưng giữ mã lỗi
- 23. cách bắt đầu dịch vụ từ các đoạn
- 24. Đường đi ngắn nhất khi không có cạnh đã cho
- 25. đầu ra đường ống của ProcessBuilder đến một ProcessBuilder khác
- 26. Đoạn trích SVGHãy cắt nội dung * ngoài * ra
- 27. Giải thích đầu ra chế độ tiết đoạn GCC
- 28. Cắt ngắn chuỗi bằng Bytes
- 29. Chia dữ liệu bị cắt thành đầu ra và đầu vào mới trong Hadoop
- 30. cách tăng độ dài đầu ra của cột sqlplus?
Bạn chỉ tìm kiếm các hình chữ nhật? – tom10