#include "Edge1d.h"
static void findPeak(int iSize, float projectMap[], float fAmpThreshold, std::vector<int>& peaks)
{
std::vector<int> sign;
for (int i = 1; i < iSize; i++) {
auto diff = projectMap[i] - projectMap[i - 1];
if (diff < 0.0f) {
sign.push_back(-1);
}
else if (diff > 0.0f) {
sign.push_back(1);
}
else {
sign.push_back(0);
}
}
for (int j = 1; j < sign.size(); j++) {
int diff = sign[j] - sign[j - 1];
if (diff != 0 && abs(projectMap[j]) > fAmpThreshold) {
peaks.push_back(j);
}
}
}
/// <summary>
/// 边缘查找工具
/// </summary>
/// <param name="tpImage">图像</param>
/// <param name="tpLineSt">卡尺起点</param>
/// <param name="tpLineEd">卡尺终点</param>
/// <param name="iCapLength">卡尺长度</param>
/// <param name="iCapWidth">卡尺宽度</param>
/// <param name="nCalipers">卡尺数量</param>
/// <param name="nFilterSize">滤波尺寸(默认为2,如果边缘较窄可以设置为1,建议范围[1,5])</param>
/// <param name="iSearchDirec">搜索方向</param>
/// <param name="dAmpThreshold">边缘阈值</param>
/// <param name="ccTransition">提取模式("all","positive","negative")</param>
/// <param name="hObject">结果</param>
/// <returns></returns>
int Edge1dFindLine(Image tpImage, MYOcsDXY tpLineSt, MYOcsDXY tpLineEd, int iCapLength, int iCapWidth, int nCalipers, int nFilterSize, int iSearchDirec, double dAmpThreshold, const char *ccTransition, IntPtr *hObject)
{
cv::Mat image = cv::Mat(tpImage.iHeight, tpImage.iWidth, MAKETYPE(tpImage.iDepth, tpImage.iChannels), tpImage.vpImage).clone();
if (image.empty()) {
return IMAGE_NOT_EXIST;
}
//灰度图
int incn = image.channels();
if (incn > 3) {
cv::cvtColor(image, image, cv::COLOR_BGRA2GRAY);
}
else if (incn == 3) {
cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
}
const int X = image.cols, Y = image.rows;
//显示用
cv::Mat cc;
cv::cvtColor(image, cc, cv::COLOR_GRAY2BGR);
//判断越界
if (tpLineSt.dX < 0 || tpLineSt.dY < 0 || tpLineSt.dX>X || tpLineSt.dY>Y || tpLineEd.dX<0 || tpLineEd.dY<0 || tpLineEd.dX>X || tpLineEd.dY>Y) {
return ILLEGAL_ARGUMENT;
}
//主轴倾角
double t;
t = atan2(tpLineEd.dY - tpLineSt.dY, tpLineEd.dX - tpLineSt.dX);
//参数限制
iCapWidth = iCapWidth <= 0 ? iCapWidth = 0 : iCapWidth - 1;
iCapLength = iCapLength <= 0 ? 8 : iCapLength;
nCalipers = nCalipers <= 0 ? 5 : nCalipers;
//直线上的坐标
float L = (float)cv::norm(cv::Point2d(tpLineSt.dX, tpLineSt.dY) - cv::Point2d(tpLineEd.dX, tpLineEd.dY));
//步长
float plusStep = (L - (float)nCalipers*(float)iCapWidth) / ((float)nCalipers + 1.0f);
//绘制profileLine
cv::arrowedLine(cc, cv::Point(cvRound(tpLineSt.dX), cvRound(tpLineSt.dY)), cv::Point(cvRound(tpLineEd.dX), cvRound(tpLineEd.dY)), cv::Scalar(255, 153, 0), 1);
//判断极性
bool anyPolarity = strcmp("all", ccTransition) == 0;
//默认过滤一半像素
float *filterK = new float[2 * nFilterSize + 1]();
//定义滤波核
for (int n = 0; n < nFilterSize; n++) {
filterK[n] = 1;
filterK[2 * nFilterSize - n] = -1;
}
cv::Mat whalf(cv::Size(2 * nFilterSize + 1, 1), CV_32FC1, filterK);
//线采样,采用双三次插值
cv::Size szMap(2 * iCapLength + 1, iCapWidth + 1);
//结果
std::vector<MYOcsDXY> *tpResults = new std::vector<MYOcsDXY>();
for (int n = 1; n <= nCalipers; n++)
{
float *pMag = new float[szMap.width*szMap.height * sizeof(float_t)];
for (int m = 0; m <= iCapWidth; m++)
{
float plusX, plusY;
plusX = ((float)n*(plusStep + (float)iCapWidth) - (float)iCapWidth + m) * (float)cos(t);
plusY = ((float)n*(plusStep + (float)iCapWidth) - (float)iCapWidth + m) * (float)sin(t);
//中轴线路径上的点
cv::Point2f pLine((float)tpLineSt.dX + plusX, (float)tpLineSt.dY + plusY);
for (int iR = -iCapLength; iR <= iCapLength; iR++) {
//待插值坐标
float _plusX, _plusY;
_plusX = (float)iR*(float)cos(t + iSearchDirec*CV_PI / 2.0) + pLine.x;
_plusY = (float)iR*(float)sin(t + iSearchDirec*CV_PI / 2.0) + pLine.y;
//防止越界
if (_plusX < 1 || _plusX >= X - 2 || _plusY < 1 || _plusY >= Y - 2) {
pMag[(iCapLength + iR) + m*szMap.width] = -1;
continue;
}
#ifdef _DEBUG
//drawPoint("", cv::Point2f(_plusX, _plusY), cv::Scalar(36, 127, 255), 1);
//画像素
float bb = (float)cos(t)*0.5f;
float aa = (float)sin(t)*0.5f;
cv::Point2f pt(_plusX, _plusY);
cv::Point2f pts[4];
pts[0].x = (float)(pt.x - aa - bb);
pts[0].y = (float)(pt.y + bb - aa);
pts[1].x = (float)(pt.x + aa - bb);
pts[1].y = (float)(pt.y - bb - aa);
pts[2].x = (float)(2 * pt.x - pts[0].x);
pts[2].y = (float)(2 * pt.y - pts[0].y);
pts[3].x = (float)(2 * pt.x - pts[1].x);
pts[3].y = (float)(2 * pt.y - pts[1].y);
for (int j = 0; j < 4; j++)
{
//drawLine("", pts[j], pts[(j + 1) % 4], cv::Scalar(255, 153, 0));
}
#endif
//整数部分
int x = cvRound(_plusX), y = cvRound(_plusY);
//小数部分
float u = abs(_plusX - ((float)x + 0.5f));
float v = abs(_plusY - ((float)y - 1.0f + 0.5f));
//插值计算灰度值
float gv = (1.0f - v)*(image.ptr<uint8_t>(y - 1)[x] * (1.0f - u) + image.ptr<uint8_t>(y - 1)[x - 1] * u)
+ v*(image.ptr<uint8_t>(y)[x] * (1.0f - u) + image.ptr<uint8_t>(y)[x - 1] * u);
//填入灰度值
pMag[(iCapLength + iR) + m*szMap.width] = gv;
}
}
//采样位置
cv::Point2f midLine((float)tpLineSt.dX + ((float)n*(plusStep + (float)iCapWidth) - (float)iCapWidth + (float)iCapWidth / 2.0f) * (float)cos(t),
(float)tpLineSt.dY + ((float)n*(plusStep + (float)iCapWidth) - (float)iCapWidth + (float)iCapWidth / 2.0f) * (float)sin(t));
//各位置采样路径
cv::Point2f midLineStart, midLineEnd;
midLineStart = cv::Point2f(-iCapLength*(float)cos(t + iSearchDirec*CV_PI / 2.0) + midLine.x, -iCapLength*(float)sin(t + iSearchDirec*CV_PI / 2.0) + midLine.y);
midLineEnd = cv::Point2f(iCapLength*(float)cos(t + iSearchDirec* CV_PI / 2) + midLine.x, iCapLength*(float)sin(t + iSearchDirec*CV_PI / 2.0) + midLine.y);
//采样图像
cv::Mat interMap(szMap, CV_32FC1, pMag);
//计算投影
cv::Mat projectedMap;
cv::reduce(interMap, projectedMap, 0, cv::REDUCE_AVG, CV_32F);
//差分过滤(TODO:加高斯滤波)
float *pFilteredMap = new float[szMap.width * sizeof(float_t)];
cv::Mat filteredMap(cv::Size(szMap.width, 1), CV_32FC1, pFilteredMap);
cv::sepFilter2D(projectedMap, filteredMap, CV_32F, whalf, cv::Mat::ones(1, 1, CV_32F));
//投影峰值查找
std::vector<int> peeks;
findPeak(szMap.width, pFilteredMap, (float)dAmpThreshold, peeks);
//存在满足幅度值的边缘
if (!peeks.empty()) {
float dist = 0; bool found = false;
//判断灰度值过滤类型
if (anyPolarity) {
//不分极性
float maxDist = 0; int maxPos = 0; found = true;
for (auto&peek : peeks) {
if (abs(pFilteredMap[peek]) > maxDist) {
maxDist = abs(pFilteredMap[peek]);
maxPos = peek;
}
}
dist = (float)maxPos;
}
else if (strcmp("positive", ccTransition) == 0) {
int maxPos = 0;
for (auto&peek : peeks) {
if (pFilteredMap[peek] > 0) {
maxPos = peek;
found = true;
break;
}
}
dist = (float)maxPos;
}
else if (strcmp("negative", ccTransition) == 0) {
int maxPos = 0;
for (auto&peek : peeks) {
if (pFilteredMap[peek] < 0) {
maxPos = peek;
found = true;
break;
}
}
dist = (float)maxPos;
}
//阈值限制,计算亚像素坐标
if (found) {
int l, m, r; float a, b, c, u;
m = (int)dist;
l = m - 1 < 0 ? m : m - 1;
r = m + 1 >= szMap.width ? m : m +
- 1
- 2
- 3
- 4
- 5
- 6
前往页