应用算法:
1、亚像素精度阈值分割
2、将轮廓分割为线和圆 (当前只做到该部分的 轮廓提取 MMP最小周长多边形近似,还未分割,后边继续......)
3、轮廓长度
4、鲁棒的线段拟合
亚像素(其实与图像整数倍放大时一样的效果,只是少了右侧和下侧一个像素的整数倍,其他都一样)的处理 双线性插值:
/*亚像素处理*(以图像左顶点为原点)/
/***************
nterval: 每两个像素之间的间隔亚像素个数
说明 屏蔽部分是用SSE学习练习的
***************/
void CPicShowDlg::SubPix(cv::Mat& src, cv::Mat& dst, int nterval/*每两个像素之间的间隔亚像素个数*/)
{
if (nterval == 0) // 无间隔
return;
nterval += 1;
//构造输出图像
int dst_rows = round((src.rows - 1) * nterval);//图像高度
int dst_cols = round((src.cols - 1) * nterval);//图像宽度
if (src.channels() == 1)
{
dst = cv::Mat::zeros(dst_rows, dst_cols, CV_8UC1); //灰度图初始
}
else
{
dst = cv::Mat::zeros(dst_rows, dst_cols, CV_8UC3); //RGB图初始
}
//
for (int i = 0; i < dst_rows; i++)
{
uchar* ptr = m_dstimg.ptr(i);
for (int j = 0; j < dst_cols; j++)
{
if (j % nterval != 0 || i % nterval != 0)
{
// 双线性插值
// 后面双线性插值用 的四个顶角
int top = i / nterval, bottom = i / nterval + 1, left = j / nterval, right = j / nterval + 1;
//与映射到原图坐标相邻的四个像素点的坐
/*双线性插值*/
// 判断是否越界
float pw = (float(i)) / 4 - top; //pw为坐标 行 的小数部分(坐标偏差)
float pv = (float(j)) / 4 - left; //pv为坐标 列 的小数部分(坐标偏差)
if (src.channels() == 1)
{
// 四个顶角的灰度值
//float grey[] = { src.at<uchar>(top, left), src.at<uchar>(top, right), src.at<uchar>(bottom, left), src.at<uchar>(bottom, right) };
//__m128 oldgrey = _mm_load_ps(grey);
针对四个顶角的 权重
//float a[4] = { 1 - pw, 1 - pw, pw, pw };
//float b[4] = { 1 - pv , pv, 1-pv, pv };
//__m128 w0 = _mm_load_ps(a);
//__m128 w1 = _mm_load_ps(b);
//__m128 ret = _mm_mul_ps(w0, w1);
//__m128 ret1 = _mm_mul_ps(ret, oldgrey);
//float result[4];
存储 将寄存器中内容保存到内存中
//_mm_store_ps(result, ret1);
//灰度图像
*ptr = (1 - pw) * (1 - pv) * src.at<uchar>(top, left) + (1 - pw) * pv * src.at<uchar>(top, right) + pw * (1 - pv) * src.at<uchar>(bottom, left) + pw * pv * src.at<uchar>(bottom, right);
}
else
{
//彩色图像
dst.at<cv::Vec3b>(i, j)[0] = (1 - pw)*(1 - pv)*src.at<cv::Vec3b>(top, left)[0] + (1 - pw)*pv*src.at<cv::Vec3b>(top, right)[0] + pw * (1 -pv)*src.at<cv::Vec3b>(bottom, left)[0] + pw * pv*src.at<cv::Vec3b>(bottom, right)[0];
dst.at<cv::Vec3b>(i, j)[1] = (1 - pw)*(1 - pv)*src.at<cv::Vec3b>(top, left)[1] + (1 - pw)*pv*src.at<cv::Vec3b>(top, right)[1] + pw * (1 -pv)*src.at<cv::Vec3b>(bottom, left)[1] + pw * pv*src.at<cv::Vec3b>(bottom, right)[1];
dst.at<cv::Vec3b>(i, j)[2] = (1 - pw)*(1 - pv)*src.at<cv::Vec3b>(top, left)[2] + (1 - pw)*pv*src.at<cv::Vec3b>(top, right)[2] + pw * (1 -pv)*src.at<cv::Vec3b>(bottom, left)[2] + pw * pv*src.at<cv::Vec3b>(bottom, right)[2];
}
}
else if(j % nterval == 0 || i % nterval == 0) // 目标图像中的像素值 是 源图像中的 j / 3位置的像素值
{
*ptr = src.at<uchar>(i / nterval, j / nterval);
}
++