基于匹配模板的术语自动翻译方法 基于openCV的形状模版匹配
日期:2023-03-11 12:39:36 / 人气: 819 / 发布者:成都翻译公司
生成旋转模版的问题openCV没有自带的旋转函数,需要通过getRotationMatrix2D生成旋转矩阵,再用warpAffine进行仿射变换。但是warpAffine生成的图形会自动进行裁剪,会带来一些问题,因此需要稍微修改(详情见imrotate函数)。openCV一些函数的源代码在内部还是进行了hal库的调用,用户没有办法修改,因此没有办法在函数内部进行算法修改。原意
果然,halcon用的顺手,人变懒了。正好有个项目需要自己写一个形状匹配的程序,就用它来实践。程序不是很复杂,速度和halcon中的find_scaled_shape_model还是有差距的。我目前不知道。如何进一步改进,暂且。如果大家有什么改进的想法,大佬们可以评论,这样你们才能继续进步。
想法
主要思想还是基于散点的重合度。虽然 openCV 自带了 matchTemplate 和 matchShape 函数,但它内部是进行遍历像素矩计算的。由于检测图像中存在干扰边缘,这些函数对于形状匹配(局部像素点集匹配)是不适合的。当然,这些功能还是很快的。目前,我不知道如何达到相同的速度。
算法实现过程中遇到几个问题:
1.生成旋转模板的问题
openCV本身没有旋转函数,需要通过getRotationMatrix2D生成旋转矩阵,然后使用warpAffine进行仿射变换。但是warpAffine生成的图形会被自动裁剪,会造成一些问题,所以需要稍微修改一下(详见imrotate函数)。
2. 遍历边缘点或进行卷积的问题
由于openCV和halcon两者在取像素上都很慢,所以只能用filter2D来做比较。不得不说openCV自带的硬件加速库还是很高效的。
3. 遍历计算速度太慢
openCV的一些函数的源码在内部还是被hal库调用了,用户没有办法修改,所以也没有办法修改函数内部的算法。尝试使用ppl库进行并行加速,效果还不错。
程序说明
(1) 先修改金字塔层级PyrLevel基于匹配模板的术语自动翻译方法,层级越大搜索速度越快。主函数中有放大的边缘图像。根据边缘是否清晰修改PyrLevel和Canny函数的阈值保证待检测图像,且模板图片边缘清晰完整。
(2)如果找不到,适当降低minScore,越接近0基于匹配模板的术语自动翻译方法,搜索相似度容忍度越大,但运行速度越慢。
函数片段
具体代码项目见
/*************************************************
Function: // CreateScaledShapeModel
Description: // 创建模版集
Input: // Template:模版图片的边缘图
PyrLevel:金字塔缩小层数
AngleStart,AngleExtent,AngleStep:旋转角度候选参数
ScaleMin,ScaleMax,ScaleStep:缩放比例候选参数
Output: // pModelImageSet,pModelPointSet,pScaleSet,pAngleSet:模版集指针
Return: // 无
Others: //
*************************************************/
void CreateScaledShapeModel(Mat Template, int PyrLevel, int AngleStart, int AngleExtent, int AngleStep, float ScaleMin, float ScaleMax, float ScaleStep, vector* pModelImageSet, vector* pModelPointSet, vector* pScaleSet, vector* pAngleSet)
{
vector ModelImageSet;
vector ModelPointSet;
vector AngleSet;
vector ScaleSet;
while (ScaleMin <= ScaleMax)
{
cout << ScaleMax << endl;
ScaleSet.push_back(ScaleMax);
ScaleMax -= ScaleStep;
}
while (AngleStart <= AngleExtent)
{
cout << AngleExtent << endl;
AngleSet.push_back(AngleExtent);
AngleExtent -= AngleStep;
}
//模版生成
for (int level = 0; level <= PyrLevel; level++)
{
Mat pyrmodelImage = Template;
for (int i = 0; i < level; i++)
{
pyrDown(pyrmodelImage, pyrmodelImage);
}
//缩放
for (int i = 0; i < ScaleSet.size(); i++)
{
Mat scaleImage;
resize(pyrmodelImage, scaleImage, Size(round(pyrmodelImage.cols*ScaleSet[i]), round(pyrmodelImage.cols*ScaleSet[i])), 0, 0, INTER_LINEAR);
//旋转
for (int j = 0; j < AngleSet.size(); j++)
{
Mat rotateImage;
imrotate(scaleImage, rotateImage, AngleSet[j]);
//threshold(rotateImage, rotateImage, 1, 255, 0);
Canny(rotateImage, rotateImage, 50, 100, 3, false);
rotateImage /= 255;
//imshow("旋转", rotateImage);
//imwrite("旋转.jpg", rotateImage);
//waitKey(0);
ModelImageSet.push_back(rotateImage);
int pointNum = 0;
for (int i = 0; i < rotateImage.cols; i++)
{
for (int j = 0; j < rotateImage.rows; j++)
{
if (rotateImage.at(Point(i, j)) != 0)
pointNum++;
}
}
ModelPointSet.push_back(pointNum);
rotateImage.release();
}
scaleImage.release();
}
}
*pModelImageSet = ModelImageSet;
*pModelPointSet = ModelPointSet;
*pAngleSet = AngleSet;
*pScaleSet = ScaleSet;
}
/*************************************************
Function: // FindScaledShapeModel
Description: // 在一张图片中搜索与模版相似的图形
Input: // Image:待检测图片
ModelImageSet,ModelPointSet,ScaleSet,AngleSet:模版集
PyrLevel:金字塔缩小层数
MinScore:筛选相似度阈值
Output: // pRow,pCol,pScale,pAngle,pScore:输出匹配到的元素参数集合的指针
Return: // 无
Others: // 使用该函数前需要先调用CreateScaledShapeModel
*************************************************/
void FindScaledShapeModel(Mat Image, vector ModelImageSet, vector ModelPointSet, vector ScaleSet, vector AngleSet, int PyrLevel, float MinScore, vector* pRow, vector * pCol, vector* pScale, vector* pAngle, vector* pScore)
{
mutex mt;
Mat modelImage = ModelImageSet[0];
vector Row;
vector Col;
vector Scale;
vector Angle;
vector Score;
bool findFlag = false;
//金字塔分层匹配
for (int level = PyrLevel; !findFlag && level >= PyrLevel; level--)
{
Mat pyrsrcImage = Image;
for (int i = 0; i < level; i++)
{
pyrDown(pyrsrcImage, pyrsrcImage);
}
int kernSize = floor(sqrt(min(pyrsrcImage.rows / 100, pyrsrcImage.cols / 100)));
Mat kern = Mat::ones(2 * kernSize + 1, 2 * kernSize + 1, CV_8U);
Mat blurImage;
filter2D(pyrsrcImage, blurImage, pyrsrcImage.depth(), kern);
//imshow("糊化原图", blurImage);
//moveWindow("糊化原图", 0, 0);
//waitKey(10);
Mat tempblurImage;
blurImage.convertTo(tempblurImage, CV_8U);
tempblurImage /= 255;
int parallelnum = ScaleSet.size() *AngleSet.size();
parallel_for(0, parallelnum, [&](int k)
{
Mat scoreImage(tempblurImage.size(), CV_16U);
Mat tempmodelImage = ModelImageSet.at(ModelImageSet.size()- 1 - k);
int temppointNum = ModelPointSet.at(ModelPointSet.size() - 1 - k);
float max_score = 0;
/*imshow("模版", tempmodelImage);
resizeWindow("模版", tempmodelImage.rows, tempmodelImage.cols);
moveWindow("模版", blurImage.cols,0);
waitKey(10);*/
//double start = static_cast(getTickCount());
filter2D(tempblurImage, scoreImage, scoreImage.depth(), tempmodelImage);
//double time = ((double)getTickCount() - start) / getTickFrequency();
//cout << "所用时间为:" << time << "秒" << endl;
mt.lock();
while (1)
{
double v_min, v_max;
int idx_min[2] = { 255,255 }, idx_max[2] = { 255, 255 };
minMaxIdx(scoreImage, &v_min, &v_max, idx_min, idx_max);
scoreImage.at(idx_max[0], idx_max[1]) = 0;
max_score = v_max / temppointNum;
//cout << "第" << level << "层" << "第" << k + 1 << "个成绩:" << max_score << endl;
if (max_score > MinScore)
{
float scale = ScaleSet[ScaleSet.size() - 1 - (k) / AngleSet.size()];
float angle = AngleSet[AngleSet.size() - 1 - (k) % AngleSet.size()];
//int selectx = (idx_max[1] - (tempmodelImage.cols - 1) / 2)*pow(2, level);
//int selecty = (idx_max[0] - (tempmodelImage.rows - 1) / 2)*pow(2, level);
//int pyrselectx = idx_max[1] - tempmodelImage.cols / 2;
//int pyrselecty = idx_max[0] - tempmodelImage.rows / 2;
Row.push_back(idx_max[1] * pow(2, level));
Col.push_back(idx_max[0] * pow(2, level));
Scale.push_back(scale);
Angle.push_back(angle);
Score.push_back(max_score);
//cout << Point(selectx, selecty) << " " << Point(pyrselectx, pyrselecty) << endl;
//rectangle(blurImage, Rect(pyrselectx, pyrselecty, tempmodelImage.cols, tempmodelImage.rows), 255, 2, 8);
//rectangle(Image, Rect(selectx, selecty, modelImage.cols / scale, modelImage.rows / scale), 255, 2, 8);
//imshow("缩放图位置", blurImage);
//imshow("原图位置", Image);
//waitKey(0);
//findFlag = true;
}
else break;
}
tempmodelImage.release();
scoreImage.release();
mt.unlock();
}
);
for (int m = 0; m < Row.size() ; m++)
{
for (int n = m+1; n < Row.size() ; n++)
{
if (abs(Row[n] - Row[m])= Score[m])
{
swap(Row[m], Row[n]);
swap(Col[m], Col[n]);
swap(Scale[m], Scale[n]);
swap(Angle[m], Angle[n]);
swap(Score[m], Score[n]);
Row.erase(Row.begin() + n);
Col.erase(Col.begin() + n);
Scale.erase(Scale.begin() + n);
Angle.erase(Angle.begin() + n);
Score.erase(Score.begin() + n);
n = m ;
}
}
}
}
*pRow = Row;
*pCol = Col;
*pScale = Scale;
*pAngle = Angle;
*pScore = Score;
}
}
void imrotate(Mat& img, Mat& newIm, double angle)
{
int heightNew = int(img.cols*fabs(sin(angle*3.14 / 180)) + img.rows * fabs(cos(angle*3.14 / 180)));
int widthNew = int(img.rows*fabs(sin(angle*3.14 / 180)) + img.cols * fabs(cos(angle*3.14 / 180)));
int len = max(img.cols, img.rows);
Point2f pt(len / 2., len / 2.);
Mat r = getRotationMatrix2D(pt, angle, 1.0);
r.at(0, 2) += (widthNew - img.cols) / 2;
r.at(1, 2) += (heightNew - img.rows) / 2;
warpAffine(img, newIm, r, Size(widthNew, heightNew), INTER_LINEAR, BORDER_REPLICATE);
}
相关阅读Relate
热门文章 Recent
- 8表翻译模板 报价单表格模板 免费版2023-03-11
- 英国签证各项材料翻译模板 英国工作签证申请条件和材料清单2023-03-11
- 专利证书翻译模板 西安正规专利证书英文翻译公司质量优良2023-03-11
- 药品说明书中英文翻译模板 药品说明书翻译_专业药品说明书翻译服务2023-03-11
- 考研英语一翻译模板下载 北京考研英语一87分经验(含考研英语一作文模板)2023-03-11
- 翻译专业个人简历模板范文 法语专业个人简历范文[Word稿]2023-03-11
- 韩国2类普通驾照韩语翻译模板 2019韩国驾照怎么考,双语版韩国驾照有何用途2023-03-11
- 澳洲大学学历认证翻译模板 德国的大学录取通知书翻译模板2023-03-11
- 德语翻译大学生个人简历模板 大学生个人简历模版.2023-03-11
- 奖状翻译模板2023-03-11


