目录
问题描述:
计算机图像处理算法经常遇到同色方块识别问题。给定一个彩色图像的颜色矩阵c,彩色图像的位置在(i,j)处,像素的颜色值是c[i][j],其中
01000000
01000000
00011100
00011100
00011100
01000000
对于寻找指定元素(此处为1),应输出最小子块边长为3,子块左上角坐标(3,3)。
简单思路
对于本人非计算机科学专业出身,表述可能不专业,抱歉。个人感觉这种编程方法类似于数字图像处理中的积分图,但因为目的是寻找特定元素最大正方形块信息,对于像素值非特定寻找元素的处理与上面的积分图有差别,可以说是一种递归+备忘录记录的动态规划过程。
/*
首先给出矩阵维数n,m,之后给出矩阵Amn的元素(好像其中只0,1,这里通用输入寻找key)和带寻找元素key,求其中值为key的块的最大边长及位置
测试用例:
n=5,m=7
0 0 0 1 0 0 0
0 1 0 0 0 0 0
0 0 1 1 1 0 0
0 0 1 1 1 0 0
0 0 1 1 1 0 1
应该输出最大边框长度3,位置第3行,第3列
类似这种题
*/
#include<iostream>
#include<exception>
#include<vector>
#include<algorithm>
#include<time.h>
using namespace std;
//函数定义
//模板类matrix头文件定义
template<class T>
class matrix
{
public:
matrix(int rows=1,int cols=1,const T&value=T()); //构造函数
vector<T>&operator[](int i); //提领运算
const vector<T>&operator[](int i)const; //提领预算
int rows()const{ return row; } //矩阵行数
int cols()const{ return col; } //矩阵列数
void resize(int rows, int cols); //重置矩阵大小
void print_matrix(ostream&out)const; //矩阵输出
private:
int row, col; //矩阵行数和列数
vector<vector<T>>mat; //向量表示的矩阵
};
//定义自己的异常
class MyMatIndUnboundException:public exception
{
virtual const char* what() const throw()
{
return "matrix index cross boarder!";
}
}myExcept;
//子函数实现功能
//构造函数
template<class T>
matrix<T>::matrix(int rows, int cols, const T& value) :row(rows), col(cols), mat(rows,vector<T>(cols,value))
{
}
//提领函数
template<class T>
vector<T>& matrix<T>::operator[](int i)
{
if (i < 0 || i >= row)throw myExcept;
return mat[i];
}
template<class T>
const vector<T>& matrix<T>::operator[](int i) const
{
if (i < 0 || i >= row)throw myExcept;
return mat[i];
}
//重置矩阵大小
template<class T>
void matrix<T>::resize(int rows, int cols)
{
if (rows == row&&cols == col)
return;
row = rows, col = cols;
mat.resize(row); //重置行数
for (int i = 0; i < row; i++)
mat[i].resize(col); //重置列数
}
//打印矩阵元素
template<class T>
void matrix<T>::print_matrix(ostream&out)const
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
cout << mat[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
/*
三邻域元素比较子函数,在maxsqurt子函数中调用
*/
int minW(matrix<int>Mat, int i,int j)
{
return(min(Mat[i - 1][j - 1], min(Mat[i - 1][j], Mat[i][j - 1])));
}
/*
函数原型:void maxsqurt(matrix<int> Mat,const int key,int&foundRow,int&foundCol,int&localLongth)
输入参数:matrix<int>Mat:输入整体矩阵
const int key:输入待寻找元素
输出参数:int&foundRow:如果找到返回最大子块右下角横坐标;否则返回0
int&foudnCol:如果找到返回最大子块右下角列坐标;否则返回0
int&localLongth:返回子块最大边长
版本信息:V1.0 Authro:QiYe005 Data:2016.9.25
*/
void maxsqurt(matrix<int> Mat,const int key,int&foundRow,int&foundCol,int&localLongth)
{
int r = Mat.rows();
int c = Mat.cols();
//首先对左边和上边进行比较
for (int i = 0; i < r; i++)
{
if (Mat[i][0] == key)
Mat[i][0] = 1;
else
Mat[i][0] = 0;
}
for (int i = 0; i < c; i++)
{
if (Mat[0][i] == key)
Mat[0][i] = 1;
else
Mat[0][i] = 0;
}
for (int i = 1; i < r; i++)
{
for (int j = 1; j < c; j++)
{
if (Mat[i][j] == key)
{
Mat[i][j] = 1 + minW(Mat, i, j);
}
else
{
Mat[i][j] = 0;
}
if (Mat[i][j]>localLongth)
{
foundRow = i;
foundCol = j;
localLongth = Mat[i][j];
}
}
}
}
int main(void)
{
try
{
//坐标系规定:x轴垂直向下,y轴水平向右,远点坐上点,起始点从1开始,注意与编程坐标的转化(-1)
matrix<int> Mat(5, 7, 0);
//改变其中最大子块长度为3,矩阵左上角坐标为(6,4)(非编程坐标)
//测试最大子块长度
int testLongth = 3;
//最大子块左上角坐标位置测试,懒得用cin读进来测试直接赋值
//注意左上角坐标(1,1),不能输入小于等于0的,且坐标加上预设宽度不能超过矩阵范围,否则报错
//这些可以通过前期判断解决,这里就不弄了
int leftupP_x = 3;
int leftupP_y = 3; //y轴水平向右,远点坐上点
//最小子块元素特定值
int specalEle = 1;
//定义返回值变量
int foundRow;
int foundCol;
int localLongth;
for (int i = leftupP_x - 1; i < testLongth + leftupP_x - 1; i++)
{
for (int j = leftupP_y - 1; j < testLongth + leftupP_y - 1; j++)
{
Mat[i][j] = specalEle;
}
}
//尝试加入随机扰动,数量不能多于定义最小子块长度,此处选取 testLongth-1次加入随机块
for (int i = 0, tem = testLongth - 1; i < tem; i++)
{
srand((unsigned)time(NULL));
int randR = rand() % (tem);
int randC = rand() % (tem);
Mat[randR][randC] = specalEle;
}
//测试开始,首先打印输入矩阵
Mat.print_matrix(cout);
//开始寻找
cout << "程序开始" << endl;
maxsqurt(Mat, specalEle, foundRow, foundCol, localLongth);
//打印结果
cout << "最大块边长为" << localLongth << "," << "块左上角横坐标为" << foundRow - localLongth+2
<< "块左上角纵坐标为" << foundCol - localLongth+2 << endl;
}
catch (exception ex)
{
cout << ex.what() << endl;
}
return 0;
}