И последний этап, ебем картинки, получаем точки.
[code]#include "opencv/cv.h"
#include "opencv/highgui.h"
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <math.h>
#include <iostream>
#include <fstream>
#include <stdio.h>
using namespace cv;
#define EPSILON 0.1
void GetLongestLine(CvArr * image, CvPoint * pt1, CvPoint * pt2);
CvPoint2D32f IntersectionPoint(CvPoint pt1, CvPoint pt2, CvPoint pt3, CvPoint pt4);
CvPoint2D32f Perpendicular(CvPoint2D32f p1, CvPoint2D32f p2, CvPoint2D32f p);
float AngleBetweenLines(CvPoint2D32f pt1, CvPoint2D32f pt2, CvPoint2D32f pt3, CvPoint2D32f pt4);
int main(int argc, char ** argv)
{
if( argc < 5)
{
printf("Not enough arguments. Must be 4.\n");
return 0;
}
int start = atoi(argv[2]); // Начальный индекс слайса.
int end = atoi(argv[3]); // Конечный индекс слайса.
std::fstream file; // Выходной файл с облаком точек.
char filename[MAX_PATH]; // Путь к файлу слайса.
IplImage * slice;
file.open(argv[4], std::ios::out);
char buf[MAX_PATH];
char buf2[5];
int sliceIndex = 0;
CvPoint2D32f center;
CvPoint2D32f ptLd;
CvPoint2D32f ptRd;
CvPoint2D32f leftLowerLine;
CvPoint2D32f rightLowerLine;
bool b = true;
for( sliceIndex = start; sliceIndex < end; sliceIndex++)
{
sprintf(filename, "%s%d.jpg", argv[1], sliceIndex);
printf("Processing of %s\n", filename);
slice = cvLoadImage(filename, CV_LOAD_IMAGE_GRAYSCALE);
CvPoint pt1, pt2, pt3, pt4; // pt1, pt2 - левый отрезок, pt3, pt4 - правый отрезок
CvPoint pt;
int width = cvGetSize(slice).width;
int height = cvGetSize(slice).height;
// Устанавливаем область интереса на левую сторону изображения.
cvSetImageROI(slice, cvRect(0, 0, width / 2, height));
// Находим самый длинный отрезок в левой стороне изображения.
GetLongestLine(slice, &pt1, &pt2);
// На правую частб экрана.
cvSetImageROI(slice, cvRect(width / 2, 0, width / 2, height));
// Самый длинный отрезок на правой стороне изобрежения.
GetLongestLine(slice, &pt3, &pt4);
pt3.x += width / 2; // снятие последствий применения ROI
pt4.x += width / 2; // снятие последствий применения ROI
cvResetImageROI(slice);
if( pt2.y < pt1.y)
{
CvPoint temp = pt1;
pt1 = pt2;
pt2 = temp;
}
if( pt3.y > pt4.y)
{
CvPoint temp2 = pt3;
pt3 = pt4;
pt4 = temp2;
}
ptLd = IntersectionPoint(pt1, pt2, cvPoint(320, 0), cvPoint(320, height));
ptRd = IntersectionPoint(pt3, pt4, cvPoint(320, 0), cvPoint(320, height));
// Точка пересечения прямых.
center = cvPoint2D32f((ptLd.x + ptRd.x) / 2.0, (ptLd.y + ptRd.y) / 2.0);
//center = IntersectionPoint(pt1, pt2, pt3, pt4);
// Нижняя точка левой линии.
leftLowerLine = cvPoint2D32f(pt1.x, pt1.y);
// Нижняя точка правой линии.
rightLowerLine = cvPoint2D32f(pt3.x, pt3.y);
// Достраиваем точку до пересечения с осью абсцисс.
// С левой абсциссой.
CvPoint2D32f ip = IntersectionPoint(cvPoint(center.x, center.y),
cvPoint(pt2.x, pt2.y/*leftLowerLine.x, leftLowerLine.y*/),
cvPoint(0, 0), cvPoint(0, height));
leftLowerLine.x = 0;
leftLowerLine.y += fabs(ip.y - leftLowerLine.y);
// С "правой" абсциссой.
ip = IntersectionPoint(cvPoint(center.x, center.y), cvPoint(pt4.x, pt4.y/*rightLowerLine.x, rightLowerLine.y*/),
cvPoint(width, 0), cvPoint(width, height));
rightLowerLine.x = width;
rightLowerLine.y += fabs(ip.y - rightLowerLine.y);
for( int x = 0; x < width; x++)
for( int y = 0; y < height; y++)
if( ((uchar*)(slice->imageData + slice->widthStep * y))[x] == 0xFF)
{
CvPoint2D32f point = cvPoint2D32f(x, y);
CvPoint2D32f pPerp = Perpendicular(center, leftLowerLine, point);
CvPoint2D32f p = cvPoint2D32f( abs(pPerp.x - center.x), abs(pPerp.y - center.y));
double mX = sqrt(pow(center.x - p.x, 2.0f) + pow(center.y - p.y, 2.0f));
pPerp = Perpendicular(center, rightLowerLine, point);
p = cvPoint2D32f( abs(pPerp.x - center.x), abs(pPerp.y - center.y));
double mY = sqrt(pow(center.x - p.x, 2.0f) + pow(center.y - p.y, 2.0f));
if( fabs((point.y - leftLowerLine.y) / (center.y - leftLowerLine.y) -
(point.x - leftLowerLine.x) / (center.x - leftLowerLine.x)) <= EPSILON )
continue;
if( fabs((point.y - rightLowerLine.y) / (center.y - rightLowerLine.y) -
(point.x - rightLowerLine.x) / (center.x - rightLowerLine.x)) <= EPSILON)
continue;
file << mX << " " << mY << " " << center.y << std::endl;
}
cvReleaseImage(&slice);
}
file.close();
return 0;
}
/* ************************************************************* */
/* Находит самую длинный отрезок на изображении. */
/* image - изображение. pt1, pt2 - координаты отрезка. */
/* ************************************************************* */
void GetLongestLine(CvArr * image, CvPoint * pt1, CvPoint * pt2)
{
CvMemStorage * storage = cvCreateMemStorage(0);
/* 1 - изображение.
2 - место, куда сохраняются найденные точки.
3 - тип метода
4 - разрешение в пикселах еденицы изображения
5 - угловое разрешение в радианах
6 - пороговое значение аккумулятора
7 - минимальная длина линии
8 - максимальный разрыв между отрезками для восприятия их как единой линии
*/
CvSeq * res = cvHoughLines2(image, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180.0, 60, 70, 5);
if( res->total > 0)
{
CvPoint * line = (CvPoint *)cvGetSeqElem(res, 0);
double maxL = sqrt(pow(abs(line[0].x - line[1].x), 2.0) + pow(abs(line[0].y - line[1].y),2.0));
double d;
int index = 0; // Индекс самого длинного отрезка.
// Находим самый длинный отрезок.
for( int i = 1; i < res->total; i++)
{
d = sqrt(pow(abs(line[i].x - line[i-1].x), 2.0) + pow(abs(line[i].y - line[i-1].y),2.0));
if( maxL < d )
{
maxL = d;
index = i;
}
}
CvPoint *maxLine = (CvPoint*)cvGetSeqElem(res, index);
*pt1 = maxLine[0];
*pt2 = maxLine[1];
}
else
{
*pt1 = cvPoint(0, 0);
*pt2 = cvPoint(0, 0);
}
cvReleaseMemStorage(&storage);
}
/* ************************************************************************ */
/* Находит точку пересечения двух прямых. */
/* pt1, pt2 - перый отрезок. pt3, pt4 - второй отрезок. */
/* Возвращает точку пересечения прямых. */
/* ************************************************************************ */
CvPoint2D32f IntersectionPoint(CvPoint pt1, CvPoint pt2, CvPoint pt3, CvPoint pt4)
{
CvPoint2D32f result;
double A1, B1, C1, A2, B2, C2;
// Находим коэффициенты уравнения первой прямой по двум точкам.
// Ax + By + C = 0
A1 = pt1.y - pt2.y;
B1 = pt2.x - pt1.x;
C1 = pt1.x * pt2.y - pt2.x * pt1.y;
// Второй прямой.
A2 = pt3.y - pt4.y;
B2 = pt4.x - pt3.x;
C2 = pt3.x * pt4.y - pt4.x * pt3.y;
// По формуле Крамера находим точку пересечения прямых.
// Если знаменатель дробей равен нулю, прямые не пересекаются.
double ZX = A1 * B2 - A2 * B1;
if( ZX == 0 )
{
result = cvPoint2D32f(0, 0);
return result;
}
result.x = -((C1 * B2 - C2 * B1) / ZX);
result.y = -((A1 * C2 - A2 * C1 ) / ZX);
return result;
}
/* ********************************************************************** */
/* Находит перпендикуляр точки к отрезку. */
/* pt1, pt2 - координаты отрезка, p - координаты точки. */
/* ********************************************************************** */
CvPoint2D32f Perpendicular(CvPoint2D32f p1, CvPoint2D32f p2, CvPoint2D32f p)
{
CvPoint2D32f c = cvPoint2D32f( p.x - p1.x, p.y - p1.y);
CvPoint2D32f b = cvPoint2D32f( p2.x - p1.x, p2.y - p1.y);
// Нормализация.
double length = sqrt( pow(b.x, 2.0f) + pow(b.y, 2.0f) );
CvPoint2D32f d = cvPoint2D32f( b.x / length, b.y / length);
double vdot = d.x * c.x + d.y * c.y;
CvPoint2D32f j = cvPoint2D32f( d.x * vdot, d.y * vdot);
return cvPoint2D32f( j.x - c.x, j.y - c.y);
}
float AngleBetweenLines(CvPoint2D32f pt1, CvPoint2D32f pt2, CvPoint2D32f pt3, CvPoint2D32f pt4)
{
double A1, B1, C1, A2, B2, C2;
// Находим коэффициенты уравнения первой прямой по двум точкам.
// Ax + By + C = 0
A1 = pt1.y - pt2.y;
B1 = pt2.x - pt1.x;
C1 = pt1.x * pt2.y - pt2.x * pt1.y;
// Второй прямой.
A2 = pt3.y - pt4.y;
B2 = pt4.x - pt3.x;
C2 = pt3.x * pt4.y - pt4.x * pt3.y;
float res = acos(
(B1 * B2 + A1 * A2) / (sqrt(pow(B1, 2.0) + pow(A2, 2.0)) * sqrt(pow(B2, 2.0) + pow(A2, 2.0)))
);
return (180.0f / CV_PI) * res;
}[/code]