#include "ContourModifyExport.h" extern "C" bool GetRotationTransMat(const MyPoint pointFix, const MyPoint pointMoveBef, const MyPoint pointMoveAft, double * rotMatDatas) { try { Point2f center = Point2f(pointFix.x, pointFix.y); float angleBef = fastAtan2(pointMoveBef.y - pointFix.y, pointMoveBef.x - pointFix.x); float angleAft = fastAtan2(pointMoveAft.y - pointFix.y, pointMoveAft.x - pointFix.x); // 因为fastAtan2求出来的角度,从x正方向起,越往逆时针方向转,角度值越大 // 但rotate矩阵中需要输入顺时针转的角度,因此这里的rotate要用bef-aft double rotate = angleBef - angleAft; double distanceBef = DistanceBetweenTwoPoints(pointMoveBef, pointFix); double distanceAft = DistanceBetweenTwoPoints(pointMoveAft, pointFix); double scale = distanceAft / distanceBef; Mat rotMat = getRotationMatrix2D(center, rotate, scale); rotMatDatas[0] = rotMat.at(0, 0); rotMatDatas[1] = rotMat.at(0, 1); rotMatDatas[2] = rotMat.at(0, 2); rotMatDatas[3] = rotMat.at(1, 0); rotMatDatas[4] = rotMat.at(1, 1); rotMatDatas[5] = rotMat.at(1, 2); return true; } catch (...) { return false; } } extern "C" bool RotateAndScalePoints(double* rotMatDatas, const int pointNum, MyPoint * pointsBef, MyPoint * pointsAft) { try { Mat rotMat(2, 3, CV_64FC1); rotMat.at(0, 0) = rotMatDatas[0]; rotMat.at(0, 1) = rotMatDatas[1]; rotMat.at(0, 2) = rotMatDatas[2]; rotMat.at(1, 0) = rotMatDatas[3]; rotMat.at(1, 1) = rotMatDatas[4]; rotMat.at(1, 2) = rotMatDatas[5]; std::vector vectBef(pointNum); std::vector vectAft(pointNum); for(int ni=0; ni vectBef(pointNum); std::vector vectAft(pointNum); for (int ni = 0; ni < pointNum; ni++) { vectBef[ni].x = pointsBef[ni].x; vectBef[ni].y = pointsBef[ni].y; } transform(vectBef, vectAft, rotMat); for (int ni = 0; ni < pointNum; ni++) { pointsAft[ni].x = vectAft[ni].x; pointsAft[ni].y = vectAft[ni].y; } return true; } catch (...) { return false; } } extern "C" bool AngleBetweenTwoLine(const MyPoint pointOrigin, const MyPoint pointAnyDir, const MyPoint pointXDir, double& angle) { try { float angleX = fastAtan2(pointXDir.y - pointOrigin.y, pointXDir.x - pointOrigin.x); float angleCur = fastAtan2(pointAnyDir.y - pointOrigin.y, pointAnyDir.x - pointOrigin.x); // 因为fastAtan2求出来的角度,从x正方向起,越往逆时针方向转,角度值越大 angle = angleCur - angleX; if(angle < 0) { angle += 360; } return true; } catch (...) { return false; } } extern "C" bool ContourArea(const MyPoint * points,const int pointNum, int& area) { try { if(pointNum<=0) { return false; } MyRect boundBox = ContourBoundBox(points, pointNum); std::vector contour(pointNum); int x, y; for (int ni = 0; ni < pointNum; ni++) { x = points[ni].x; y = points[ni].y; contour[ni].x = x - boundBox.left; contour[ni].y = y - boundBox.top; } Mat img = Mat::zeros(boundBox.bottom - boundBox.top +1, boundBox.right - boundBox.left + 1, CV_8UC1); std::vector> contours; contours.push_back(contour); cv::drawContours(img, contours,0, 255, FILLED, LINE_8); area = cv::countNonZero(img); img.release(); return true; } catch (...) { return false; } } extern "C" bool GetContourPointByPoint(const MyPoint * pointsBef, const int pointNum, MyPoint * pointsAft, int& pointNumAft) { try { int kernelSize = 5; int blurSize = 3; int boundBoxExpandSize = max(kernelSize,blurSize) * 2+1; if (pointNum <= 0) { return false; } MyRect boundBox = ContourBoundBox(pointsBef, pointNum); boundBox.top -= boundBoxExpandSize; boundBox.left -= boundBoxExpandSize; boundBox.right += boundBoxExpandSize; boundBox.bottom += boundBoxExpandSize; std::vector contour(pointNum); int x, y; for (int ni = 0; ni < pointNum; ni++) { x = pointsBef[ni].x; y = pointsBef[ni].y; contour[ni].x = x - boundBox.left; contour[ni].y = y - boundBox.top; } Size imgSize = Size(boundBox.right - boundBox.left + 1,boundBox.bottom - boundBox.top + 1); Mat img = Mat::zeros(imgSize, CV_8UC1); std::vector> contours; contours.push_back(contour); cv::drawContours(img, contours, 0,255, FILLED, LINE_AA); cv::medianBlur(img, img, blurSize); cv::threshold(img, img, 128, 255, THRESH_BINARY); std::vector> contoursFound; std::vector hierarchy; cv::findContours(img, contoursFound, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE); int maxArea = 0; int index = -1; for(size_t ni=0; ni maxArea) { index = ni; maxArea = area; } } if(index!=-1) { std::vector contourSel = contoursFound[index]; int len = contourSel.size(); for(int ni=0; ni contour(pointNum); int x, y; for (int ni = 0; ni < pointNum; ni++) { x = pointsBef[ni].x; y = pointsBef[ni].y; contour[ni].x = x - boundBox.left; contour[ni].y = y - boundBox.top; } Size imgSize = Size(boundBox.right - boundBox.left + 1, boundBox.bottom - boundBox.top + 1); Mat img = Mat::zeros(imgSize, CV_8UC1); std::vector> contours; contours.push_back(contour); cv::drawContours(img, contours, 0, 255, 1, LINE_AA); cv::threshold(img, img, 128, 255, THRESH_BINARY); std::vector> contoursFound; std::vector hierarchy; cv::findContours(img, contoursFound, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE); int maxArea = 0; int index = -1; for (size_t ni = 0; ni < contoursFound.size(); ni++) { Mat imgSingleContour = Mat::zeros(imgSize, CV_8UC1); drawContours(imgSingleContour, contoursFound, ni, 255, 1, LINE_AA); int area = countNonZero(imgSingleContour); imgSingleContour.release(); if (area > maxArea) { index = ni; maxArea = area; } } if (index != -1) { std::vector contourSel = contoursFound[index]; int len = contourSel.size(); for (int ni = 0; ni < len; ni++) { pointsAft[ni].x = contourSel[ni].x + boundBox.left; pointsAft[ni].y = contourSel[ni].y + boundBox.top; } pointNumAft = len; } img.release(); return true; } catch (...) { return false; } } extern "C" bool GetContourPointByPointEliminateSelfCross(const MyPoint * pointsBef, const int pointNum, MyPoint * pointsAft, int& pointNumAft) { try { int blurSize = 3; int boundBoxExpandSize = blurSize * 2 + 1; if (pointNum <= 0) { return false; } // 插值,让轮廓线至少是逐像素相连的 std::vector pointsPixelByPixel; MyPoint pointPre, pointNi; for(int ni=0; ni> crossPoints; for(int ni=0; ni< newPointCount;ni++) { int closePointIndex = 0; if(CheckIfContourSelfCrossed(pointsPixelByPixel, ni, preStartCount, closePointIndex)) { MyPoint pointNow = pointsPixelByPixel[closePointIndex]; // 起点和终点必须闭合,因此不要把起点和终点误判为一对交叉点 MyPoint pointStart= pointsPixelByPixel[0]; MyPoint pointEnd = pointsPixelByPixel[newPointCount-1]; double distanceToStart = DistanceBetweenTwoPoints(pointNow, pointStart); double distanceToEnd = DistanceBetweenTwoPoints(pointNow, pointEnd); if(distanceToStart<1.5 && distanceToEnd<1.5) { continue; } int existCount = crossPoints.size(); if(existCount>0) { // 不要在一个位置处重复添加交叉点对 int prePointFirst = crossPoints[existCount - 1].first; int prePointSecond = crossPoints[existCount - 1].second; MyPoint pointPre = pointsPixelByPixel[prePointSecond]; double distance = DistanceBetweenTwoPoints(pointNow, pointPre); if(ni - prePointFirst cross; cross.first = ni; cross.second = closePointIndex; crossPoints.push_back(cross); } } // 整理所有交叉点,组成一对一对的,这一对轮廓线中,可以删除将较长的那一组中间的所有点吸附到较短的那一条上 int crossPointCount = crossPoints.size(); if(crossPointCount >0) { // 未完成,自交叉的可能情况比较多,暂未找到合适的方法清除掉自交叉的部分 } // 计算所有轮廓点的外边框 MyRect boundBox = ContourBoundBox(pointsBef, pointNum); boundBox.top -= boundBoxExpandSize; boundBox.left -= boundBoxExpandSize; boundBox.right += boundBoxExpandSize; boundBox.bottom += boundBoxExpandSize; std::vector contour(pointNum); int x, y; for (int ni = 0; ni < pointNum; ni++) { x = pointsBef[ni].x; y = pointsBef[ni].y; contour[ni].x = x - boundBox.left; contour[ni].y = y - boundBox.top; } Size imgSize = Size(boundBox.right - boundBox.left + 1, boundBox.bottom - boundBox.top + 1); Mat img = Mat::zeros(imgSize, CV_8UC1); std::vector> contours; contours.push_back(contour); cv::drawContours(img, contours, 0, 255, FILLED, LINE_AA); cv::medianBlur(img, img, blurSize); cv::threshold(img, img, 128, 255, THRESH_BINARY); std::vector> contoursFound; std::vector hierarchy; cv::findContours(img, contoursFound, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE); int maxArea = 0; int index = -1; for (size_t ni = 0; ni < contoursFound.size(); ni++) { Mat imgSingleContour = Mat::zeros(imgSize, CV_8UC1); drawContours(imgSingleContour, contoursFound, ni, 255, FILLED, 0); int area = countNonZero(imgSingleContour); imgSingleContour.release(); if (area > maxArea) { index = ni; } } if (index != -1) { std::vector contourSel = contoursFound[index]; int len = contourSel.size(); for (int ni = 0; ni < len; ni++) { pointsAft[ni].x = contourSel[ni].x + boundBox.left; pointsAft[ni].y = contourSel[ni].y + boundBox.top; } pointNumAft = len; } img.release(); return true; } catch (...) { return false; } } extern "C" bool LineContourIntersection(const MyPoint * points, const int pointNum, const MyPoint lineStart, const MyPoint lineEnd, const int touchDistance, bool extended, InterecttionsResults & results) { try { if (pointNum <= 0) { return false; } // 遍历轮廓上的点,当该点和直线的距离小于阈值,则认为是符合要求的点 std::vector intersections; double distanceStartToEnd = DistanceBetweenTwoPoints(lineStart, lineEnd); for(int ni=0;ni180) { angleWithStart = 360 - angleWithStart; } // 与直线的距离 double distanceToLine = sin(DegToRad(angleWithStart)) * distanceToStart; if(distanceToLine <=touchDistance) { if(extended || distanceToEnd< touchDistance || distanceToStart<= touchDistance || abs(distanceToEnd +distanceToStart - distanceStartToEnd)<=touchDistance ) { InterecttionsDetails intersection; intersection.indexInContour = ni; intersection.distanceToLineStart = distanceToStart; intersection.distanceToLineEnd = distanceToEnd; intersections.push_back(intersection); } } } // 如果一个交点都没有,直接退出 if (intersections.size() <= 0) { results.intersectWithLineStart = false; results.intersectWithLineEnd = false; results.indexInContourIntersectionStart = -1; results.indexInContourIntersectionEnd = -1; return true; } // 将交点按其与起点的距离排序 sort(intersections.begin(), intersections.end(), SortIntersectionByDistanceToStartIncrease); // 找到离起点近的那个交点(必须是离start比离end近) std::vector selected; if (intersections[0].distanceToLineStart <= intersections[0].distanceToLineEnd) { selected.push_back(intersections[0]); } // 将交点按其与终点的距离排序 sort(intersections.begin(), intersections.end(), SortIntersectionByDistanceToEndIncrease); if (selected.size() > 0) { // 顺序将所有临近点删除 std::vector adjacent; bool preSearch = true; bool backSearch = true; int preIndex = selected[0].indexInContour; int backIndex = selected[0].indexInContour; adjacent.push_back(selected[0].indexInContour); while (preSearch || backSearch) { // 向前搜索 if (preSearch) { // 循环自减(index 小于0时,需要注意反向) preIndex -= 1; if (preIndex < 0) { preIndex += pointNum; } bool contains = false; for (auto intersection : intersections) { if(intersection.indexInContour == preIndex) { contains = true; adjacent.push_back(preIndex); break; } } preSearch = contains; } // 向后搜索 if (backSearch) { // 循环自增(index 大于keyPointNum时,需要注意反向) backIndex += 1; if(backIndex >= pointNum) { backIndex -= pointNum; } bool contains = false; for (auto intersection : intersections) { if (intersection.indexInContour == backIndex) { contains = true; adjacent.push_back(backIndex); break; } } backSearch = contains; if(adjacent.size()>= intersections.size()) { break; } } } int pointToAddIndex = intersections[0].indexInContour; bool add = true; for (auto value : adjacent) { if(value == pointToAddIndex) { add = false; break; } } if(add) { selected.push_back(intersections[0]); } } else { if (intersections[0].distanceToLineEnd < intersections[0].distanceToLineStart) { selected.push_back(intersections[0]); } } if(selected.size()<=0) { results.intersectWithLineStart = false; results.intersectWithLineEnd = false; results.indexInContourIntersectionStart = -1; results.indexInContourIntersectionEnd = -1; return true; } else if(selected.size() == 2) { results.intersectWithLineStart = true; results.intersectWithLineEnd = true; results.indexInContourIntersectionStart = selected[0].indexInContour; results.indexInContourIntersectionEnd = selected[1].indexInContour; return true; } else { if(selected[0].distanceToLineStart <= selected[0].distanceToLineEnd) { results.intersectWithLineStart = true; results.intersectWithLineEnd = false; results.indexInContourIntersectionStart = selected[0].indexInContour; results.indexInContourIntersectionEnd = -1; } else { results.intersectWithLineEnd = true; results.intersectWithLineStart = false; results.indexInContourIntersectionEnd = selected[1].indexInContour; results.indexInContourIntersectionStart = -1; } return false; } } catch (...) { return false; } } MyRect ContourBoundBox(const MyPoint* points, const int pointNum) { int left = points[0].x; int right = points[0].x; int top = points[0].y; int bottom = points[0].y; int x, y; for (int ni = 1; ni < pointNum; ni++) { x = points[ni].x; y = points[ni].y; if (x < left) { left = x; } if(x>right) { right = x; } if(ybottom) { bottom = y; } } MyRect boundBox; boundBox.left = left; boundBox.right = right; boundBox.top = top; boundBox.bottom = bottom; return boundBox; } double DistanceBetweenTwoPoints(const MyPoint pointOne, const MyPoint pointOther) { return sqrt(powf((pointOne.x - pointOther.x), 2) + powf((pointOne.y - pointOther.y), 2)); } double DistanceBetweenTwoRect(const MyRect rectOne, const MyRect rectOther) { int left = max(rectOne.left, rectOther.left); int top = max(rectOne.top, rectOther.top); int right = min(rectOne.right, rectOther.right); int bottom = min(rectOne.bottom, rectOther.bottom); // 两个矩形有交集 if(left<=right && top <=bottom) { return 0; } // x方向有平行区域 if(left<=right) { return abs(bottom - top); } // y 方向有平行区域 if(top<=bottom) { return abs(right - left); } // 没有交集,则left,top,right,bottom 构成的两个点之间的距离就是最短距离 int disw = left - right; int dish = bottom - top; return sqrt(powf(disw, 2) + powf(dish, 2)); } bool SortPointByDistanceIncrease(std::paira, std::pairb) { return a.first < b.first; } bool SortIntersectionByDistanceToStartIncrease(InterecttionsDetails a, InterecttionsDetails b) { return a.distanceToLineStart < b.distanceToLineStart; } bool SortIntersectionByDistanceToEndIncrease(InterecttionsDetails a, InterecttionsDetails b) { return a.distanceToLineEnd < b.distanceToLineEnd; } bool AddPointsPixelByPixel(std::vector& contours, MyPoint pointToAdd, MyPoint pointPre) { double distance = DistanceBetweenTwoPoints(pointToAdd, pointPre); // 距离为0,不添加 if(distance<=0) { return false; } // 距离小于等于根号2,可以直接添加,不用插值 if(distance < 1.5) { contours.push_back(pointToAdd); return true; } // 距离大于根号2,需要插值 int deltaX = pointToAdd.x - pointPre.x; int deltaY = pointToAdd.y - pointPre.y; int deltaXAbs = abs(deltaX); int deltaYAbs = abs(deltaY); double ratio; // 看沿着哪个方向插值 // x方向的差异较大,则沿着x方向插值 if(deltaXAbs >deltaYAbs) { for(int ni=1; ni contours, int curIndex, int preStartCount,int& indexOfClosePoint) { if(curIndex < preStartCount) { return false; } MyPoint pointCur = contours[curIndex]; for(int ni=curIndex - preStartCount; ni>=0; ni--) { double distance = DistanceBetweenTwoPoints(pointCur, contours[ni]); if(distance<=1.5) { indexOfClosePoint = ni; return true; } } return false; }