<Demura>AMOLED屏幕子像素定位

此代码为练手代码,代码缺乏规范性和稳定性,仅作参考和交流!

AMOLED屏幕子像素定位

1、相机拍摄原图及局部放大图片
<Demura>AMOLED屏幕子像素定位_第1张图片

<Demura>AMOLED屏幕子像素定位_第2张图片

// 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);
}

<Demura>AMOLED屏幕子像素定位_第3张图片
<Demura>AMOLED屏幕子像素定位_第4张图片
<Demura>AMOLED屏幕子像素定位_第5张图片

你可能感兴趣的:(【AOI】屏幕缺陷检测算法)