编程练习:同色方块识别问题

目录

问题描述:

   计算机图像处理算法经常遇到同色方块识别问题。给定一个彩色图像的颜色矩阵c,彩色图像的位置在(i,j)处,像素的颜色值是c[i][j],其中 0c[i][j]k,0i<m,0j<n ,编程以简单二值图像为例,之后可以推导出其他量化空间寻找最小方块,例如:


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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值