2020-10-21 17:24:01 +02:00

256 lines
8.0 KiB
C++

#include "image_edge_detection.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "C:/devel/opencv/build/install/include/opencv2/line_descriptor.hpp"
#include <opencv2\flann.hpp>
using namespace cv;
using namespace std;
cv::Mat qimage_to_mat_ref(QImage &img)
{
return cv::Mat(img.height(), img.width(),
CV_8UC4, img.bits(), img.bytesPerLine());
}
bool mergeSegments(std::vector< cv::line_descriptor::KeyLine > & kp, float closeendpointlessthan = 7, float parallelifanglelessthan = 15, float parallellinescloserthan = 7 ){
std::vector< cv::line_descriptor::KeyLine > res;
std::vector<bool> joined;
bool retv;
joined.resize(kp.size(),false);
cv::Mat features = Mat::zeros(kp.size() * 2, 2, CV_32F);
for (int i = 0; i < kp.size(); ++i){
features.at<float>(i * 2 , 0) = kp[i].startPointX;
features.at<float>(i * 2 , 1) = kp[i].startPointY;
features.at<float>(i * 2 + 1, 0) = kp[i].endPointX;
features.at<float>(i * 2 + 1, 1) = kp[i].endPointY;
}
flann::Index flann_index(features, flann::KDTreeIndexParams());
for (int i = 0; i < kp.size()*2; ++i) if(!joined[i/2]){
cv::Mat querypoint(1, 2, CV_32F);
std::vector<int> indices;
std::vector<float> distances(2,10000.0);
querypoint.at<float>(0, 0) = features.at<float>(i, 0);
querypoint.at<float>(0, 1) = features.at<float>(i, 1);
flann_index.knnSearch(querypoint, indices, distances, 2);
int j = indices[1];
if (!joined[j / 2] && (i / 2 != j / 2) && distances[1] <= closeendpointlessthan){ // pixels
cv::Point2f s00, s01, s10, s11;
// test collinearity
s00.x = features.at<float>(((i % 2) == 0) ? i : i - 1, 0);
s00.y = features.at<float>(((i % 2) == 0) ? i : i - 1, 1);
s01.x = features.at<float>(((i % 2) == 0) ? i + 1 : i, 0);
s01.y = features.at<float>(((i % 2) == 0) ? i + 1 : i, 1);
s10.x = features.at<float>(((j % 2) == 0) ? j : j - 1, 0);
s10.y = features.at<float>(((j % 2) == 0) ? j : j - 1, 1);
s11.x = features.at<float>(((j % 2) == 0) ? j + 1 : j, 0);
s11.y = features.at<float>(((j % 2) == 0) ? j + 1 : j, 1);
cv::Point2f v0 = s01 - s00;
v0 = v0 / sqrt((float)v0.dot(v0));
cv::Point2f v1 = s11 - s10;
v1 = v1 / sqrt((float)v1.dot(v1));
float alpha = fabs(asin(fabs(v0.cross(v1))));
cv::Point2f ij0, ij1;
ij0.x = features.at<float>(i, 0);
ij0.y = features.at<float>(i, 1);
ij1.x = features.at<float>(j, 0);
ij1.y = features.at<float>(j, 1);
float t0 = (ij1 - s00).dot(v0);
cv::Point2f c0 = s00 + v0*t0;
float l0 = (c0 - ij1).dot(c0 - ij1);
float t1 = (ij0 - s10).dot(v1);
cv::Point2f c1 = s10 + v1*t1;
float l1 = (c1 - ij0).dot(c1 - ij0);
if ((alpha < M_PI * parallelifanglelessthan / 180.0) &&
(l0 <parallellinescloserthan) &&
(l1 <parallellinescloserthan))
{
cv::line_descriptor::KeyLine newSegm;
newSegm.startPointX = features.at<float>(((i % 2) == 0) ? i + 1 : i - 1, 0);
newSegm.startPointY = features.at<float>(((i % 2) == 0) ? i + 1 : i - 1, 1);
newSegm.endPointX = features.at<float>(((j % 2) == 0) ? j + 1 : j - 1, 0);
newSegm.endPointY = features.at<float>(((j % 2) == 0) ? j + 1 : j - 1, 1);
newSegm.octave = 0;
res.push_back(newSegm);
//{ // DEBUG STUFF
// FILE*f = fopen("_qr.txt", "a");
// fprintf(f, "Merge:%d %d, %f\n < %f %f> < %f %f>\n < %f %f> < %f %f> \n alpha %f, l0 %f l1 %f \n",
// i, j, distances[1],
// features.at<float>(((i % 2) == 0) ? i : i - 1, 0),
// features.at<float>(((i % 2) == 0) ? i : i - 1, 1),
// features.at<float>(((i % 2) == 0) ? i + 1 : i, 0),
// features.at<float>(((i % 2) == 0) ? i + 1 : i, 1),
// features.at<float>(((j % 2) == 0) ? j : j - 1, 0),
// features.at<float>(((j % 2) == 0) ? j : j - 1, 1),
// features.at<float>(((j % 2) == 0) ? j + 1 : j, 0),
// features.at<float>(((j % 2) == 0) ? j + 1 : j, 1),
// alpha,l0,l1
// );
// fprintf(f, " v0 %f %f, v1 %f %f\n",s00.x,s00.y,s11.x,s11.y);
// fprintf(f, "new-> < %f %f> < %f %f> \n", newSegm.startPointX, newSegm.startPointY, newSegm.endPointX, newSegm.endPointY);
// fclose(f);
//}
joined[j / 2] = true;
joined[i / 2] = true;
}
}
}
for (int i = 0; i < kp.size(); ++i)
if (!joined[i])
res.push_back(kp[i]);
retv = (kp.size() != res.size());
// {FILE*f = fopen("_sizes.txt", "w"); fprintf(f, "%d %d", kp.size(), res.size()); fclose(f); }
kp = res;
return retv;
}
void saveEdgesImage(const char * name, cv::Mat o, std::vector< cv::line_descriptor::KeyLine > keypoints)
{
/* draw lines extracted from octave 0 */
if (o.channels() == 1)
cvtColor(o, o, COLOR_GRAY2BGR);
for (size_t i = 0; i < keypoints.size(); i++)
{
cv::line_descriptor::KeyLine kl = keypoints[i];
if (kl.octave == 0)
{
/* get a random color */
int R = int(kl.startPointX + kl.startPointY) % 255;
int G = int(kl.startPointX * kl.startPointY) % 255;
int B = int(kl.startPointX - kl.startPointY) % 255;
/* get extremes of line */
Point pt1 = Point2f(kl.startPointX, kl.startPointY);
Point pt2 = Point2f(kl.endPointX, kl.endPointY);
/* draw line */
line(o, pt1, pt2, Scalar(B, G, R), 3);
}
}
cv::imwrite(name, o);
}
int detect_edges(QImage input, const char * filename)
{
Mat src1 = qimage_to_mat_ref(input);
Mat src2;
Mat gray, edge, draw;
// cv::imwrite("src1.jpg", src1);
cvtColor(src1, gray, CV_RGB2GRAY);
cv::resize(gray, src2, cv::Size(gray.cols / 2, gray.rows / 2 ));
cv::Mat output = src2.clone();
cv::Mat output1 = src2.clone();
cv::Mat corners = src2.clone();
cv::Mat mask = Mat::ones(src1.size(), CV_8UC1);
std::vector< cv::line_descriptor::KeyLine > keypoints;
cv::Ptr<cv::line_descriptor::LSDDetector> lsd = cv::line_descriptor::LSDDetector::createLSDDetector();
//{ // DEBUG READ EDGES FROM FILE
// FILE * f = fopen("edges.txt", "r");
// int n = 0;
// fscanf(f, "%d\n", &n);
// keypoints.resize(n);
// for (int y = 00; y < n; ++y)
// {
// fscanf(f, "%f %f %f %f", &keypoints[y].startPointX, &keypoints[y].startPointY,
// &keypoints[y].endPointX, &keypoints[y].endPointY);
// keypoints[y].octave = 0;
// }
// fclose(f);
//}
lsd->detect(src2, keypoints, 2, 1);
{ // corner harris
cv::cornerHarris(src2, corners, 2, 3, 0.04);
/// Normalizing
cv::Mat corners_norm, corners_norm_sclaed;
normalize(corners, corners_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
convertScaleAbs(corners_norm, corners_norm_sclaed);
/// Drawing a circle around corners
for (int j = 0; j < corners_norm.rows; j++)
{
for (int i = 0; i < corners_norm.cols; i++)
{
if ((int)corners_norm.at<float>(j, i) > 100)
{
circle(corners_norm_sclaed, Point(i, j), 5, Scalar(0), 2, 8, 0);
}
}
}
cv::imwrite("corners.jpg", corners_norm_sclaed);
}
//{ // DEBUG WRITE OUT EDGES
// FILE * f = fopen("edges.txt", "w");
// fprintf(f, "%d\n", keypoints.size());
// for (int y = 00; y < keypoints.size(); ++y)
// {
// fprintf(f, "%f %f %f %f\n", keypoints[y].startPointX, keypoints[y].startPointY,
// keypoints[y].endPointX, keypoints[y].endPointY);
// }
// fclose(f);
//}
saveEdgesImage("imageedges.jpg", output, keypoints);
/* simple greedy edge simplfication */
while(
mergeSegments(keypoints)
);
saveEdgesImage("merged.jpg", output1, keypoints);
//cv::Mat outputC = src2.clone();
//std::vector<std::vector<cv::Point> > contours;
//std::vector<cv::Vec4i> hierarchy;
//cv::findContours(src2, contours, hierarchy,
// RETR_LIST /*RETR_EXTERNAL RETR_LIST ,RETR_CCOMP ,RETR_TREE RETR_FLOODFILL */,
// CHAIN_APPROX_SIMPLE);
//for (int ii = 0; ii < contours.size(); ++ii){
// int R = (rand() % (int)(255 + 1));
// int G = (rand() % (int)(255 + 1));
// int B = (rand() % (int)(255 + 1));
// for (int jj = 0; jj < contours[ii].size(); ++jj)
// line(outputC, contours[ii][jj], contours[ii][(jj + 1) % contours[ii].size()], Scalar(B, G, R), 3);
//}
//cv::imwrite("contour.jpg", outputC);
return 0;
}