此代码为练手代码,代码缺乏规范性和稳定性,仅作参考和交流!
// Sub-pixel positioning2.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include
#include
using namespace std;
using namespace cv;
float WrapImage(Mat image);//图片旋转调整,返回一个斜率
Point2f GetMaxPixel(Mat gray, Point2f p);//得到一个像素周围灰度值最大的像素点
vector GetPixel(Mat image);//阈值分割及子像素点提取
vector AdjustPixel(vector pt, float k);//像素点根据斜率进行调整及从小到大排序
vector> GetRowPixel(vector pt, float k);//根据每行子像素的y坐标相差4个像素点以内来获得各行子像素
void LineRow(Mat origin, vector> row, string str);//连接各行子像素成直线
int _tmain(int argc, _TCHAR* argv[])
{
string dir_path = "E:\\image-R\\";
vector file_vec;
glob(dir_path + "*.bmp", file_vec, false);
Mat image = imread("E:\\image-R\\img_R255.bmp");
float k = WrapImage(image);
vector pt = GetPixel(image);
vector pot = AdjustPixel(pt, k);
vector> p_row = GetRowPixel(pot, k);
string filename = "F:\\image-R\\img_R255.bmp";
LineRow(image, p_row, filename);
//RGB三通道9张灰阶图像,进行9次循环
for (int i = 0; i < 9; i++)
{
if (file_vec[i] == "E:\\image-R\\img_R255.bmp")
continue;
Mat image = imread(file_vec[i]);
string str = file_vec[i];
str[0] = 'F';
LineRow(image, p_row, str);
}
system("pause");
waitKey(0);
return 0;
}
图片旋转调整,返回一个斜率
float WrapImage(Mat image)
{
//灰度、二值化、膨胀
Mat gray, bin, dil;
cvtColor(image,gray, COLOR_RGB2GRAY);
threshold(gray,bin, 10, 255, THRESH_BINARY);
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
dilate(bin, dil, element);
//轮廓最小矩形,寻找旋转角度和旋转中心
vector> contours;
vector hierarchy;
findContours(dil,contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
Rect boundrect;
RotatedRect rect;
for(int i = 0; i < contours.size(); i++)
{
Point2f r[4];
rect= minAreaRect(contours[i]);
boundrect= boundingRect(Mat(contours[i]));
rect.points(r);
rectangle(dil,Point(boundrect.x, boundrect.y), Point(boundrect.x + boundrect.width,boundrect.y + boundrect.height), Scalar(255, 255, 255), 2, 8);
for(int j = 0; j < 4; j++)
{
line(dil,r[j], r[(j + 1) % 4], Scalar(255, 255, 255), 2, 8);
}
}
//方法一:直接旋转图片,但是这样操作处理时间长
////旋转角度:rect.angle
////旋转中心:rect.center
////旋转矩阵
////cout<< rect.angle << endl;
////cout<< tan(rect.angle) << endl;
////Ma trot_mat = getRotationMatrix2D(rect.center, rect.angle, 1);
////Mat rot_img;
////warpAffine(image,rot_img, rot_mat, image.size(), INTER_NEAREST);
//方法二:直接对像素矩阵进行处理,节省时间
//得到的角度进行转换,角度->弧度->斜率
float angle = rect.angle / 180 * CV_PI;
return tan(angle);
}
得到一个像素周围灰度值最大的像素点
Point2f GetMaxPixel(Mat gray, Point2f p)
{
int a[8][2] = { { -1, -1 }, { 0, -1 }, { 1, -1 }, { -1, 0 }, { 1, 0 }, { -1, 1 }, {0, 1 }, { 1, 1 } };
Point2f maxPoint;
maxPoint.x= p.x;
maxPoint.y= p.y;
for(int i = 0; i < 8; i++)
{
Point2f tmp;
tmp.x= p.x + a[i][0];
tmp.y= p.y + a[i][1];
//对一个像素的邻域8个像素进行比较,选取灰度值最高的像素点作为子像素(灯珠)的中心
if(gray.at(maxPoint) < gray.at(tmp))
{
maxPoint.x= tmp.x;
maxPoint.y= tmp.y;
}
}
return maxPoint;
}
阈值分割及子像素点提取
vector GetPixel(Mat image)
{
Mat gray;
cvtColor(image,gray, COLOR_BGR2GRAY);
Matth_img;
//全局阈值分割
threshold(gray,th_img, 40, 255, THRESH_BINARY);
//连通域获取中心坐标
Mat labels, stats, centroids;
int nccomps = connectedComponentsWithStats(th_img, labels, stats, centroids);
vector pt;
for(int i = 0; i < centroids.rows; i++)
{
Point2f p;
p.x= centroids.at(i, 0);
p.y= centroids.at(i, 1);
Point2f maxPoint = GetMaxPixel(gray, p);
pt.push_back(p);
}
//返回所有子像素点坐标
return pt;
}
按照 y大小排序,找出行像素
bool cmp(Point2f a, Point2f b)
{
return a.y < b.y;
}
像素点根据斜率进行调整及从小到大排序
vector AdjustPixel(vector pt, float k)
{
for(int i = 0; i < pt.size(); i++)
{
pt[i].y= pt[i].y - k*pt[i].x;
}
sort(pt.begin(),pt.end(), cmp);
return pt;
}
根据每行子像素的y坐标相差4个像素点以内来获得各行子像素
vector> GetRowPixel(vector pt, float k)
{
vector> row;
for(int i = 0; i < pt.size(); i++)
{
vector sig_row;
sig_row.push_back(pt[i]);
Point2f pp = pt[i++];
while((pt[i].y<(pp.y + 4)) && (pt[i].y>(pp.y - 4)) &&(ipt.size() - 1)
break;
}
i--;
row.push_back(sig_row);
}
for(int i = 0; i < row.size(); i++)
{
for(int j = 0; j < row[i].size(); j++)
{
for(int k = j; k < row[i].size(); k++)
{
if(row[i][j].x >= row[i][k].x)
swap(row[i][j],row[i][k]);
}
}
}
//反转,转换回原图像坐标
for(int i = 0; i < row.size(); i++)
{
for(int j = 0; j < row[i].size(); j++)
{
row[i][j].y+= row[i][j].x*k;
}
}
return row;
}
连接各行子像素成直线
void LineRow(Mat origin,vector> row, string str)
{
for(int i = 0; i < row.size(); i++)
{
for(int j = 0; j < row[i].size() - 1; j++)
{
line(origin,row[i][j], row[i][j + 1], Scalar(0, 255, 255), 0.05);
}
}
imwrite(str,origin);
}