/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2015, Smart Engines Ltd, all rights reserved. // Copyright (C) 2015, Institute for Information Transmission Problems of the Russian Academy of Sciences (Kharkevich Institute), all rights reserved. // Copyright (C) 2015, Dmitry Nikolaev, Simon Karpenko, Michail Aliev, Elena Kuznetsova, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ #include "precomp.hpp" namespace cv { namespace ximgproc { #if defined(_WIN32) && !defined(int32_t) typedef __int32 int32_t; #endif template<typename T, int D, HoughOp Op> struct HoughOperator { }; #define SPECIALIZE_HOUGHOP(TOp, body) \ template<typename T, int D> \ struct HoughOperator<T, D, TOp> { \ static void operate(T *pDst, T *pSrc0, T* pSrc1, int len) { \ Mat dst (Size(1, len), D, pDst); \ Mat src0(Size(1, len), D, pSrc0); \ Mat src1(Size(1, len), D, pSrc1); \ body; \ } \ }; SPECIALIZE_HOUGHOP(FHT_ADD, add(src0, src1, dst)); SPECIALIZE_HOUGHOP(FHT_MIN, min(src0, src1, dst)); SPECIALIZE_HOUGHOP(FHT_MAX, max(src0, src1, dst)); SPECIALIZE_HOUGHOP(FHT_AVE, addWeighted(src0, 0.5, src1, 0.5, 0.0, dst)); #undef SPECIALIZE_HOUGHOP //----------------------fht---------------------------------------------------- template <typename T, int D, HoughOp OP> void fhtCore(Mat &img0, Mat &img1, int32_t y0, int32_t h, bool isPositiveShift, int level, double aspl) { if (level <= 0) return; CV_Assert(h > 0); if (h == 1) { if ((aspl != 0.0) && (level == 1)) { int w = img0.cols; uchar* pLine0 = img0.data + img0.step * y0; uchar* pLine1 = img1.data + img1.step * y0; int dLine = cvRound(y0 * aspl); dLine = dLine % w; dLine = dLine * (int)(img1.elemSize()); int wLine = img0.cols * (int)(img0.elemSize()); memcpy(pLine0, pLine1 + wLine - dLine, dLine); memcpy(pLine0 + dLine, pLine1, wLine - dLine); } else { memcpy(img0.data + img0.step * y0, img1.data + img1.step * y0, img0.cols * (int)(img0.elemSize())); } return; } const int32_t k = h >> 1; fhtCore<T, D, OP>(img1, img0, y0, k, isPositiveShift, level - 1, aspl); fhtCore<T, D, OP>(img1, img0, y0 + k, h - k, isPositiveShift, level - 1, aspl); int au = 2 * k - 2; int ad = 2 * h - 2 * k - 2; int b = h - 1; int d = 2 * h - 2; int w = img0.cols; int wm = (h / w + 1) * w; for (int32_t s = 0; s < h; s++) { int su = (s * au + b) / d; int sd = (s * ad + b) / d; int rd = isPositiveShift ? sd - s : s - sd; rd = (rd + wm) % w; uchar *pLine0 = img0.data + img0.step * (y0 + s); uchar *pLineU = img1.data + img1.step * (y0 + su); uchar *pLineD = img1.data + img1.step * (y0 + k + sd); int w0 = img0.channels() * rd; int w1 = img0.channels() * (w - rd); if ((aspl != 0.0) && (level == 1)) { int dU = cvRound((y0 + su) * aspl); dU = dU % w; dU *= img0.channels(); int dD = cvRound((y0 + k + sd) * aspl); dD = dD % w; dD *= img0.channels(); int wB = w * img0.channels(); int dX = dD - dU; if (w0 >= dX) { if (w0 >= dD) { HoughOperator<T, D, OP>::operate((T *)pLine0 + dU, (T *)pLineU, (T *)pLineD + (w0 - dX), w1 + dX); HoughOperator<T, D, OP>::operate((T *)pLine0 + (w1 + dD), (T *)pLineU + (w1 + dX), (T *)pLineD, w0 - dD); HoughOperator<T, D, OP>::operate((T *)pLine0, (T *)pLineU + (wB - dU), (T *)pLineD + (w0 - dD), dU); } else { HoughOperator<T, D, OP>::operate((T *)pLine0 + dU, (T *)pLineU, (T *)pLineD + (w0 - dX), wB - dU); HoughOperator<T, D, OP>::operate((T *)pLine0, (T *)pLineU + (wB - dU), (T *)pLineD + (w0 + wB - dD), dD - w0); HoughOperator<T, D, OP>::operate((T *)pLine0 + (dD - w0), (T *)pLineU + (w1 + dX), (T *)pLineD, w0 - dX); } } else { HoughOperator<T, D, OP>::operate((T *)pLine0 + dU, (T *)pLineU, (T *)pLineD + (wB - (dX - w0)), dX - w0); HoughOperator<T, D, OP>::operate((T *)pLine0 + (dD - w0), (T *)pLineU + (dX - w0), (T *)pLineD, wB - (dX - w0) - dU); HoughOperator<T, D, OP>::operate((T *)pLine0, (T *)pLineU + (wB - dU), (T *)pLineD + (wB - (dX - w0) - dU), dU); } } else { HoughOperator<T, D, OP>::operate((T *)pLine0, (T *)pLineU, (T *)pLineD + w0, w1); HoughOperator<T, D, OP>::operate((T *)pLine0 + w1, (T *)pLineU + w1, (T *)pLineD, w0); } } } template <typename T, int D, HoughOp Op> void fhtVoT(Mat &img0, Mat &img1, bool isPositiveShift, double aspl) { int level = 0; for (int thres = 1; img0.rows > thres; thres <<= 1) level++; fhtCore<T, D, Op>(img0, img1, 0, img0.rows, isPositiveShift, level, aspl); } template <typename T, int D> void fhtVo(Mat &img0, Mat &img1, bool isPositiveShift, int operation, double aspl) { switch (operation) { case FHT_ADD: fhtVoT<T, D, FHT_ADD>(img0, img1, isPositiveShift, aspl); break; case FHT_AVE: fhtVoT<T, D, FHT_AVE>(img0, img1, isPositiveShift, aspl); break; case FHT_MAX: fhtVoT<T, D, FHT_MAX>(img0, img1, isPositiveShift, aspl); break; case FHT_MIN: fhtVoT<T, D, FHT_MIN>(img0, img1, isPositiveShift, aspl); break; default: CV_Error_(CV_StsNotImplemented, ("Unknown operation %d", operation)); break; } } static void fhtVo(Mat &img0, Mat &img1, bool isPositiveShift, int operation, double aspl) { int const depth = img0.depth(); switch (depth) { case CV_8U: fhtVo<uchar, CV_8UC1>(img0, img1, isPositiveShift, operation, aspl); break; case CV_8S: fhtVo<schar, CV_8SC1>(img0, img1, isPositiveShift, operation, aspl); break; case CV_16U: fhtVo<ushort, CV_16UC1>(img0, img1, isPositiveShift, operation, aspl); break; case CV_16S: fhtVo<short, CV_16SC1>(img0, img1, isPositiveShift, operation, aspl); break; case CV_32S: fhtVo<int, CV_32SC1>(img0, img1, isPositiveShift, operation, aspl); break; case CV_32F: fhtVo<float, CV_32FC1>(img0, img1, isPositiveShift, operation, aspl); break; case CV_64F: fhtVo<double, CV_64FC1>(img0, img1, isPositiveShift, operation, aspl); break; default: CV_Error_(CV_StsNotImplemented, ("Unknown depth %d", depth)); break; } } static void FHT(Mat &dst, const Mat &src, int operation, bool isVertical, bool isClockwise, double aspl) { CV_Assert(dst.cols > 0 && dst.rows > 0); CV_Assert(src.channels() == dst.channels()); if (isVertical) CV_Assert(src.cols == dst.cols && src.rows == dst.rows); else CV_Assert(src.cols == dst.rows && src.rows == dst.cols); int level = 0; for (int thres = 1; dst.rows > thres; thres <<= 1) level++; Mat tmp; src.convertTo(tmp, dst.type()); if (!isVertical) transpose(tmp, tmp); tmp.copyTo(dst); fhtVo(dst, tmp, isVertical ? isClockwise : !isClockwise, operation, aspl); } static void calculateFHTQuadrant(Mat &dst, const Mat &src, int operation, int quadrant) { bool bVert = true; bool bClock = true; double aspl = 0.0; switch (quadrant) { case ARO_315_0: bVert = true; bClock = false; break; case ARO_0_45: bVert = true; bClock = true; break; case ARO_45_90: bVert = false; bClock = false; break; case ARO_90_135: bVert = false; bClock = true; break; case ARO_CTR_VER: bVert = true; bClock = false; aspl = 0.5; break; case ARO_CTR_HOR: bVert = false; bClock = true; aspl = 0.5; break; default: CV_Error_(CV_StsNotImplemented, ("Unknown quadrant %d", quadrant)); } FHT(dst, src, operation, bVert, bClock, aspl); } static void createDstFhtMat(OutputArray dst, InputArray src, int depth, int angleRange) { int const rows = src.size().height; int const cols = src.size().width; int const channels = src.channels(); int wd = cols + rows; int ht = 0; switch (angleRange) { case ARO_315_0: case ARO_0_45: case ARO_CTR_VER: ht = rows; break; case ARO_45_90: case ARO_90_135: case ARO_CTR_HOR: ht = cols; break; case ARO_315_45: ht = 2 * rows - 1; break; case ARO_45_135: ht = 2 * cols - 1; break; case ARO_315_135: ht = 2 * (cols + rows) - 3; break; default: CV_Error_(CV_StsNotImplemented, ("Unknown angleRange %d", angleRange)); } dst.create(ht, wd, CV_MAKETYPE(depth, channels)); } static void createFHTSrc(Mat &srcFull, const Mat &src, int angleRange) { bool verticalTiling = false; switch (angleRange) { case ARO_315_0: case ARO_0_45: case ARO_CTR_VER: case ARO_315_45: verticalTiling = false; break; case ARO_45_90: case ARO_90_135: case ARO_CTR_HOR: case ARO_45_135: verticalTiling = true; break; default: CV_Error_(CV_StsNotImplemented, ("Unknown angleRange %d", angleRange)); } int wd = verticalTiling ? src.cols : src.cols + src.rows; int ht = verticalTiling ? src.cols + src.rows : src.rows; srcFull = Mat(ht, wd, src.type()); Mat imgReg; if (verticalTiling) imgReg = Mat(srcFull, Rect(0, src.rows, src.cols, src.cols)); else imgReg = Mat(srcFull, Rect(src.cols, 0, src.rows, src.rows)); imgReg = Mat::zeros(imgReg.size(), imgReg.type()); imgReg = Mat(srcFull, Rect(0, 0, src.cols, src.rows)); src.copyTo(imgReg); } static void setFHTDstRegion(Mat &dstRegion, const Mat &dst, const Mat &src, int quadrant, int angleRange) { int base = -1; switch (angleRange) { case ARO_315_0: case ARO_315_45: case ARO_315_135: base = 0; break; case ARO_0_45: base = 1; break; case ARO_45_90: case ARO_45_135: base = 2; break; case ARO_90_135: base = 3; break; default: CV_Error_(CV_StsNotImplemented, ("Unknown angleRange %d", angleRange)); } int quad = -1; switch (quadrant) { case ARO_315_0: quad = 0; break; case ARO_0_45: quad = 1; break; case ARO_45_90: quad = 2; break; case ARO_90_135: quad = 3; break; default: CV_Error_(CV_StsNotImplemented, ("Unknown quadrant %d", quadrant)); } if (quad < base) quad += 4; int shift = 0; for (int i = base; i < quad; i++) shift += (i & 2) ? src.cols - 1 : src.rows - 1; const int ht = (quad & 2) ? src.cols : src.rows; dstRegion = Mat(dst, Rect(0, shift, src.rows + src.cols, ht)); } static void rotateLineRightCyclic(uchar *pLine, uchar *pBuf, int len, int shift) { shift = shift % len; shift = (shift + len) % len; memcpy(pBuf, pLine, len); memcpy(pLine + shift, pBuf, len - shift); if (shift > 0) memcpy(pLine, pBuf + len - shift, shift); } static void skewQuadrant(Mat &quad, const Mat &src, uchar *pBuf, int quadrant) { CV_Assert(pBuf); const int wd = src.cols; const int ht = src.rows; double start = 0.; double step = .5; switch (quadrant) { case ARO_315_0: case ARO_CTR_VER: step = -.5; start = ht - 0.5; break; case ARO_0_45: step = -.5; start = ht * .5; break; case ARO_45_90: break; case ARO_90_135: case ARO_CTR_HOR: start = wd * .5 - 0.5; break; default: CV_Error_(CV_StsNotImplemented, ("Unknown quadrant %d", quadrant)); } const int pixlen = static_cast<int>(quad.elemSize()); const int len = quad.cols * pixlen; for (int y = 0; y < quad.rows; y++) { uchar *pLine = quad.ptr(y); int shift = static_cast<int>(start + step * y) * pixlen; rotateLineRightCyclic(pLine, pBuf, len, shift); } } void FastHoughTransform(InputArray src, OutputArray dst, int dstMatDepth, int angleRange, int operation, int makeSkew) { Mat srcMat = src.getMat(); if (!srcMat.isContinuous()) srcMat = srcMat.clone(); CV_Assert(srcMat.cols > 0 && srcMat.rows > 0); createDstFhtMat(dst, src, dstMatDepth, angleRange); Mat dstMat = dst.getMat(); Mat imgRegDst; const int len = dstMat.cols * static_cast<int>(dstMat.elemSize()); CV_Assert(len > 0); std::vector<uchar> buf_(len); uchar *buf(&buf_[0]); if (angleRange == ARO_315_135) { { Mat imgSrc; createFHTSrc(imgSrc, srcMat, ARO_315_45); setFHTDstRegion(imgRegDst, dstMat, srcMat, ARO_315_0, angleRange); calculateFHTQuadrant(imgRegDst, imgSrc, operation, ARO_315_0); flip(imgRegDst, imgRegDst, 0); if (HDO_DESKEW == makeSkew) skewQuadrant(imgRegDst, imgSrc, buf, ARO_315_0); setFHTDstRegion(imgRegDst, dstMat, srcMat, ARO_0_45, angleRange); calculateFHTQuadrant(imgRegDst, imgSrc, operation, ARO_0_45); if (HDO_DESKEW == makeSkew) skewQuadrant(imgRegDst, imgSrc, buf, ARO_0_45); } { Mat imgSrc; createFHTSrc(imgSrc, srcMat, ARO_45_135); setFHTDstRegion(imgRegDst, dstMat, srcMat, ARO_45_90, angleRange); calculateFHTQuadrant(imgRegDst, imgSrc, operation, ARO_45_90); flip(imgRegDst, imgRegDst, 0); if (HDO_DESKEW == makeSkew) skewQuadrant(imgRegDst, imgSrc, buf, ARO_45_90); setFHTDstRegion(imgRegDst, dstMat, srcMat, ARO_90_135, angleRange); calculateFHTQuadrant(imgRegDst, imgSrc, operation, ARO_90_135); if (HDO_DESKEW == makeSkew) skewQuadrant(imgRegDst, imgSrc, buf, ARO_90_135); } return; } Mat imgSrc; createFHTSrc(imgSrc, srcMat, angleRange); switch (angleRange) { case ARO_315_0: calculateFHTQuadrant(dstMat, imgSrc, operation, angleRange); flip(dstMat, dstMat, 0); if (HDO_DESKEW == makeSkew) skewQuadrant(dstMat, imgSrc, buf, angleRange); return; case ARO_0_45: calculateFHTQuadrant(dstMat, imgSrc, operation, angleRange); if (HDO_DESKEW == makeSkew) skewQuadrant(dstMat, imgSrc, buf, angleRange); return; case ARO_45_90: calculateFHTQuadrant(dstMat, imgSrc, operation, angleRange); flip(dstMat, dstMat, 0); if (HDO_DESKEW == makeSkew) skewQuadrant(dstMat, imgSrc, buf, angleRange); return; case ARO_90_135: calculateFHTQuadrant(dstMat, imgSrc, operation, angleRange); if (HDO_DESKEW == makeSkew) skewQuadrant(dstMat, imgSrc, buf, angleRange); return; case ARO_315_45: setFHTDstRegion(imgRegDst, dstMat, srcMat, ARO_315_0, angleRange); calculateFHTQuadrant(imgRegDst, imgSrc, operation, ARO_315_0); flip(imgRegDst, imgRegDst, 0); if (HDO_DESKEW == makeSkew) skewQuadrant(imgRegDst, imgSrc, buf, ARO_315_0); setFHTDstRegion(imgRegDst, dstMat, srcMat, ARO_0_45, angleRange); calculateFHTQuadrant(imgRegDst, imgSrc, operation, ARO_0_45); if (HDO_DESKEW == makeSkew) skewQuadrant(imgRegDst, imgSrc, buf, ARO_0_45); return; case ARO_45_135: setFHTDstRegion(imgRegDst, dstMat, srcMat, ARO_45_90, angleRange); calculateFHTQuadrant(imgRegDst, imgSrc, operation, ARO_45_90); flip(imgRegDst, imgRegDst, 0); if (HDO_DESKEW == makeSkew) skewQuadrant(imgRegDst, imgSrc, buf, ARO_45_90); setFHTDstRegion(imgRegDst, dstMat, srcMat, ARO_90_135, angleRange); calculateFHTQuadrant(imgRegDst, imgSrc, operation, ARO_90_135); if (HDO_DESKEW == makeSkew) skewQuadrant(imgRegDst, imgSrc, buf, ARO_90_135); return; case ARO_CTR_VER: calculateFHTQuadrant(dstMat, imgSrc, operation, angleRange); flip(dstMat, dstMat, 0); if (HDO_DESKEW == makeSkew) skewQuadrant(dstMat, imgSrc, buf, angleRange); return; case ARO_CTR_HOR: calculateFHTQuadrant(dstMat, imgSrc, operation, angleRange); if (HDO_DESKEW == makeSkew) skewQuadrant(dstMat, imgSrc, buf, angleRange); return; default: CV_Error_(CV_StsNotImplemented, ("Unknown angleRange %d", angleRange)); } } //----------------------------------------------------------------------------- //----------------------fht point2line----------------------------------------- struct LineSegment { Point u, v; LineSegment(const Point _u, const Point _v) : u(_u), v(_v) { } }; static void getRawPoint(Point &rawHoughPoint, int &quadRawPoint, const Point &givenHoughPoint, const Mat &srcImgInfo, int angleRange, int makeSkew) { int base = -1; switch (angleRange) { case ARO_315_0: case ARO_315_45: case ARO_CTR_VER: case ARO_315_135: base = 0; break; case ARO_0_45: base = 1; break; case ARO_45_90: case ARO_45_135: base = 2; break; case ARO_90_135: case ARO_CTR_HOR: base = 3; break; default: CV_Error_(CV_StsNotImplemented, ("Unknown angleRange %d", angleRange)); } int const cols = srcImgInfo.cols; int const rows = srcImgInfo.rows; rawHoughPoint.y = givenHoughPoint.y; int quad = 0, qsize = 0; for (quad = base; quad < 4; quad++) { qsize = (quad & 2) ? cols - 1 : rows - 1; if (rawHoughPoint.y <= qsize) break; rawHoughPoint.y -= qsize; } if (quad >= 4) CV_Error(CV_StsInternal, ""); quadRawPoint = quad; double skewShift = 0.0; if (makeSkew == HDO_DESKEW) { switch (quad) { case 0: skewShift = rows - (rawHoughPoint.y + 1) * 0.5; break; case 1: skewShift = (rows - rawHoughPoint.y) * 0.5; break; case 2: skewShift = rawHoughPoint.y * 0.5; break; default: skewShift = 0.5 * (cols + rawHoughPoint.y - 1); break; } } rawHoughPoint.x = givenHoughPoint.x - static_cast<int>(skewShift); if (rawHoughPoint.x < 0) rawHoughPoint.x = rows + cols + rawHoughPoint.x; } static bool checkRawPoint(const Point &rawHoughPoint, int quadRawPoint, const Mat &srcImgInfo) { int const cols = srcImgInfo.cols; int const rows = srcImgInfo.rows; switch (quadRawPoint) { case 0: //down left triangle on FHT if (rawHoughPoint.x - cols <= rawHoughPoint.y && rawHoughPoint.x - cols >= 0) return false; break; case 1: //up right triangle on FHT if (rawHoughPoint.x - cols >= rawHoughPoint.y) return false; break; case 2: //up right triangle on up-down FHT image if (rawHoughPoint.x - rows >= cols - 1 - rawHoughPoint.y) return false; break; default: //down left triangle on up-down FHT image if (rawHoughPoint.x - rows <= cols - 1 - rawHoughPoint.y && rawHoughPoint.x - rows >= 0) return false; break; } return true; } static void shiftLineSegment(LineSegment &segment, const Point &shift) { segment.u.x += shift.x; segment.v.x += shift.x; segment.u.y += shift.y; segment.v.y += shift.y; } static void lineFactors(double &a, double &b, double &c, const Point &point1, const Point &point2) { CV_Assert(point1.x != point2.x || point1.y != point2.y); Point vectorSegment(point2.x - point1.x, point2.y - point1.y); a = - vectorSegment.y; b = vectorSegment.x; c = - (a * point1.x + b * point1.y); } static void crossSegments(Point &point, const LineSegment &line1, const LineSegment &line2) { double a1 = 0.0, b1 = 0.0, c1 = 0.0; double a2 = 0.0, b2 = 0.0, c2 = 0.0; lineFactors(a1, b1, c1, line1.u, line1.v); lineFactors(a2, b2, c2, line2.u, line2.v); double uLine1onLine2 = a2 * line1.u.x + b2 * line1.u.y + c2; double vLine1onLine2 = a2 * line1.v.x + b2 * line1.v.y + c2; double ULine2onLine1 = a1 * line2.u.x + b1 * line2.u.y + c1; double VLine2onLine1 = a1 * line2.v.x + b1 * line2.v.y + c1; CV_Assert(ULine2onLine1 != 0 || VLine2onLine1 != 0 || uLine1onLine2 != 0 || vLine1onLine2 != 0); CV_Assert(ULine2onLine1 * VLine2onLine1 <= 0 && uLine1onLine2 * vLine1onLine2 <= 0); static const double double_eps = 1e-10; CV_Assert(std::abs(uLine1onLine2 - vLine1onLine2) >= double_eps); double mul = uLine1onLine2 / (uLine1onLine2 - vLine1onLine2); point.x = cvRound(line1.u.x + mul * (line1.v.x - line1.u.x)); point.y = cvRound(line1.u.y + mul * (line1.v.y - line1.u.y)); } Vec4i HoughPoint2Line(const Point &houghPoint, InputArray srcImgInfo, int angleRange, int makeSkew, int rules) { Mat srcImgInfoMat = srcImgInfo.getMat(); int const cols = srcImgInfoMat.cols; int const rows = srcImgInfoMat.rows; CV_Assert(houghPoint.y >= 0); CV_Assert(houghPoint.x < cols + rows); int quad = 0; Point rawPoint(0, 0); getRawPoint(rawPoint, quad, houghPoint, srcImgInfoMat, angleRange, makeSkew); bool ret = checkRawPoint(rawPoint, quad, srcImgInfoMat); if (!(rules & RO_IGNORE_BORDERS)) { CV_Assert(ret); } LineSegment dstLine(Point(0, 0), Point(0, 0)); switch (quad) { case 0: dstLine.v.y = rows - 1; dstLine.u.x = rawPoint.x; dstLine.v.x = dstLine.u.x + rows - rawPoint.y - 1; break; case 1: dstLine.v.y = rows - 1; dstLine.u.x = rawPoint.x; dstLine.v.x = dstLine.u.x - rawPoint.y; break; case 2: dstLine.v.x = cols - 1; dstLine.u.y = rawPoint.x; dstLine.v.y = dstLine.u.y - cols + rawPoint.y + 1; break; default: dstLine.v.x = cols - 1; dstLine.u.y = rawPoint.x; dstLine.v.y = dstLine.u.y + rawPoint.y; break; } if (angleRange == ARO_CTR_VER) { int shift = cvRound(0.5 * dstLine.u.y); shift = shift % (cols + rows); dstLine.u.x = dstLine.u.x - shift; shift = cvRound(0.5 * dstLine.v.y); shift = shift % (cols + rows); dstLine.v.x = dstLine.v.x - shift; } else if (angleRange == ARO_CTR_HOR) { int shift = cvRound(0.5 * dstLine.u.x); shift = shift % (cols + rows); dstLine.u.y = dstLine.u.y - shift; shift = cvRound(0.5 * dstLine.v.x); shift = shift % (cols + rows); dstLine.v.y = dstLine.v.y - shift; } if (!ret) { return Vec4i(dstLine.v.x, dstLine.v.y, dstLine.u.x, dstLine.u.y); } if (rules & RO_IGNORE_BORDERS) { switch (quad) { case 0: if (dstLine.v.x > cols + rows - 1) { Point shiftVector(-(cols + rows), 0); shiftLineSegment(dstLine, shiftVector); } break; case 3: if (dstLine.v.y > rows + cols - 1) { Point shiftVector(0, -(cols + rows)); shiftLineSegment(dstLine, shiftVector); } break; default: break; } return Vec4i(dstLine.v.x, dstLine.v.y, dstLine.u.x, dstLine.u.y); } Point minIntersectPoint(0, 0); Point minLeftUpSrcPoint(0, 0); Point minRightUpSrcPoint(cols - 1, 0); Point minLeftDownSrcPoint(0, rows - 1); Point minRightDownSrcPoint(cols - 1, rows - 1); switch (quad) { case 0: if (dstLine.v.x > cols + rows - 1) { LineSegment minRightToDstLine(Point(cols + rows, 0), Point(cols + rows, rows - 1) ); crossSegments(minIntersectPoint, dstLine, minRightToDstLine); dstLine.u.y = minIntersectPoint.y; dstLine.u.x = 0; dstLine.v.x = dstLine.v.x - (cols + rows); } if (dstLine.v.x > cols - 1) { LineSegment minRightSrcLine(minRightUpSrcPoint, minRightDownSrcPoint); crossSegments(minIntersectPoint, dstLine, minRightSrcLine); dstLine.v.y = minIntersectPoint.y; dstLine.v.x = cols - 1; } break; case 1: if (dstLine.v.x < 0) { LineSegment minLeftSrcLine(minLeftUpSrcPoint, minLeftDownSrcPoint); crossSegments(minIntersectPoint, dstLine, minLeftSrcLine); dstLine.v.y = minIntersectPoint.y; dstLine.v.x = 0; } if (dstLine.u.x > cols - 1) { LineSegment minRightSrcLine(minRightUpSrcPoint, minRightDownSrcPoint); crossSegments(minIntersectPoint, dstLine, minRightSrcLine); dstLine.u.y = minIntersectPoint.y; dstLine.u.x = cols - 1; } break; case 2: if (dstLine.v.y < 0) { LineSegment minTopSrcLine(minLeftUpSrcPoint, minRightUpSrcPoint); crossSegments(minIntersectPoint, dstLine, minTopSrcLine); dstLine.v.x = minIntersectPoint.x; dstLine.v.y = 0; } if (dstLine.u.y > rows - 1) { LineSegment minBottomSrcLine(minLeftDownSrcPoint, minRightDownSrcPoint); crossSegments(minIntersectPoint, dstLine, minBottomSrcLine ); dstLine.u.x = minIntersectPoint.x; dstLine.u.y = rows - 1; } break; default: if (dstLine.v.y > rows + cols - 1) { LineSegment minDownToDstLine(Point(0, rows + cols), Point(cols - 1, rows + cols)); crossSegments(minIntersectPoint, dstLine, minDownToDstLine); dstLine.u.x = minIntersectPoint.x; dstLine.u.y = 0; dstLine.v.y = dstLine.v.y - (rows + cols); } if (dstLine.v.y > rows - 1) { LineSegment minBottomSrcLine(minLeftDownSrcPoint, minRightDownSrcPoint); crossSegments(minIntersectPoint, dstLine, minBottomSrcLine); dstLine.v.x = minIntersectPoint.x; dstLine.v.y = rows - 1; } break; } return Vec4i(dstLine.v.x, dstLine.v.y, dstLine.u.x, dstLine.u.y); } //----------------------------------------------------------------------------- } } // namespace cv::ximgproc