POJ 1009 Edge Detection

本文介绍了POJ 1009题目中的边缘检测问题,强调每个输出像素点至少与输入图像的一个像素相邻。通过反证法证明了这一命题,并讨论了特殊情况,特别是边界情况的处理。原文链接提供了一个清晰的解释和解决方案,包括代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

读完此题后,总的感觉就是没有具体的确定的优化方案,所以迟迟没法下手敲代码。于是在网上搜了一下解题报告,看了好几篇仍是感觉好凌乱。直到看了这一篇http://liangsun.org/posts/poj-1009-edge-detection-report/后,思路才算清晰起来。

引文首先给出了一个命题:每一个在输出结果中的像素点在原图像中的位置至少跟一个输入像素点相邻。

注:这里的相邻是指两个像素点的位置间距为-1+{0,-width,+width},0+{-width,+width}, 1+{0,-width,+width}。

这里面重复一下原著的证明,帮助自己加深一下理解。

证明采用的是反证法,即证明:一个像素点在原图像中所在的位置不跟任何输入像素点相邻,那么此像素点必定不会出现在输出结果中。


证:假如在图1中,x跟任何输入像素点都不相邻,那么b=a,c=b,e=x,g=h,h=f,并且由a,d,f也不是像素点可以得到图2,此时我们就看出红框的x跟其左边的x的最大差绝对值是一样的。所以红框的x必定不会在输出结果中。

如果x位于边界处,如在最左边,见图3,根据相邻点的定义,红框的x跟其左边的x的最大差绝对值也是一样的。

x位于最右边的情况为图4,红框的x仍然跟其左边的x的最大差绝对值是一样的。

定理的证明到现在基本完毕,但是有一种特殊情况没有考虑到,对于x处于最左边的情况,当处于图5的情况时,就有可能出现意外。


这个时候,红框的x与其左边的x的最大差绝对值有可能不一样了。原著是把height*width位置处也作为一个输入像素点。可以这样理解,对于原图像,如果还存在输入像素点的话,那么height*width肯定是下一个输入像素点。这样就不难理解height*width也作为一个像素输入点了。这样理解也就使得要证的命题是完全正确的。

注:如果无法理解height*width作为输入像素点的话,完全可以把红框的x作为一个特殊位置点,单独进行一下计算就行。至于红框x周围的点为啥不需要计算,自己简单推推就ok了。

原著的解题报告虽然是English版的,但是写的很通俗易懂,代码也很给力,读者可以参阅poj-1009-edge-detection-report

还是附上自己的代码:

#include <iostream>
#include <vector>
#include <map>
#include <cstdlib>
#include <cmath>
#include <utility>
#include <algorithm>

using namespace std;

int height, width;
vector<int> sum;
vector<pair<int,int> > imgI;
map<int, int> imgO;

int GetPixel(int pos)
{
    for(int i = 0; i < imgI.size(); ++i)
	if( pos < sum[i] )
	    return imgI[i].second;
}

void Cal(int pos)
{
    if( imgO.find( pos ) != imgO.end() )
	return ;
	
    int row = pos/width, col = pos%width;
    if( pos < 0 || pos >= sum.back() )
	return ;

    int pixel = GetPixel( pos );

    int maxDiff = 0;
    for(int i = row - 1; i <= row + 1; ++i)
	for(int j = col - 1; j <= col + 1; ++j)
	{
	    if( i < 0 || i >= height || j < 0 || j >= width)
		continue;
	    int nPos = i*width + j;
	    //cout << row << " " << col << " -> " << nPos/width << " " << nPos%width << endl;
	    int nPixel = GetPixel( nPos );
	    maxDiff = max( maxDiff, abs(pixel-nPixel) );
	}
    imgO[pos] = maxDiff;
}

void Work()
{
    for(int i = 0; i < imgI.size(); ++i)
    {
	int pos = imgI[i].first;

	for(int k = -1; k <= 1; ++k)
	    for(int j = -1; j <= 1; ++j)
	    {
		int nPos = pos + k*width + j;
		Cal( nPos );
	    }
    }
    Cal( sum.back() - width );
}

void Print()
{
    map<int,int>::iterator iter = imgO.begin();
    int curPos = iter->first, curPixel = iter->second;
    while( iter != imgO.end() )
    {
	if( iter->second != curPixel )
	{
	    cout << curPixel << " " << (iter->first - curPos) << endl;
	    curPos = iter->first;
	    curPixel = iter->second;
	}
	++iter;
    }
    cout << curPixel << " " << (sum.back() - curPos) << endl;
    cout << "0 0" << endl;
}

int main()
{
    while( cin >> width && width )
    {
	cout << width << endl;
	sum.clear();
	imgI.clear();
	imgO.clear();
	int pixel, len;
	int pos = 0;
	while( cin >> pixel >> len )
	{
	    if( !pixel && !len )
		break;
	    imgI.push_back( make_pair(pos, pixel) );
	    pos += len;
	    sum.push_back( pos );
	}
	height = sum.back()/width;
	Work();
	Print();
    }
    cout << 0 << endl;
    return 0;
}

GetPixel的二分查找实现为:

int GetPixel(int pos)
{
    /*
    for(int i = 0; i < imgI.size(); ++i)
	if( pos < sum[i] )
	    return imgI[i].second;
	    */
    int low = 0, high = imgI.size() - 1;
    while( low <= high )
    {
	int mid = (low + high)/2;
	if( pos < sum[mid] )
	    high = mid - 1;
	else low = mid + 1;
    }
    return imgI[low].second;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值