c语言floodfill算法,OpenCV入门教程之十五水漫金山:OpenCV漫水填充算法(Floodfill)...

本文主要是介绍c语言floodfill算法,OpenCV入门教程之十五水漫金山:OpenCV漫水填充算法(Floodfill)...,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

接着,来看一个关于Floodfill的简单的调用范例:

//-----------------------------------【头文件包含部分】---------------------------------------

// 描述:包含程序所依赖的头文件

//----------------------------------------------------------------------------------------------

#include

#include

//-----------------------------------【命名空间声明部分】---------------------------------------

// 描述:包含程序所使用的命名空间

//-----------------------------------------------------------------------------------------------

using namespace cv;

//-----------------------------------【main( )函数】--------------------------------------------

// 描述:控制台应用程序的入口函数,我们的程序从这里开始

//-----------------------------------------------------------------------------------------------

int main( )

{

Mat src = imread("1.jpg");

imshow("【原始图】",src);

Rect ccomp;

floodFill(src, Point(50,300), Scalar(155, 255,55), &ccomp, Scalar(20, 20, 20),Scalar(20, 20, 20));

imshow("【效果图】",src);

waitKey(0);

return 0;

}

运行截图,原始图:

946ab91939c7db1caee4150d6022199c.png

效果图:

4cdc44d2916d8e2e6bfab28d77dbc7d8.png

五、floodFill函数在OpenCV中的实现源代码

这个部分贴出OpenCV中本文相关函数的源码实现细节,来给想了解实现细节的小伙伴们参考。浅墨暂时不在源码的细节上挖深作详细注释。

5.1 OpenCV2.X中两个版本的floodFill函数源码

第一个,不带mask版本的floodFill:

int cv::floodFill( InputOutputArray _image,Point seedPoint,

Scalar newVal, Rect* rect,

Scalar loDiff, ScalarupDiff, int flags )

{

CvConnectedComp ccomp;

CvMat c_image = _image.getMat();

cvFloodFill(&c_image, seedPoint, newVal, loDiff, upDiff, &ccomp,flags, 0);

if( rect )

*rect = ccomp.rect;

return cvRound(ccomp.area);

}

第二个,带mask版本的floodFill:

int cv::floodFill( InputOutputArray _image,InputOutputArray _mask,

Point seedPoint, ScalarnewVal, Rect* rect,

Scalar loDiff, ScalarupDiff, int flags )

{

CvConnectedComp ccomp;

CvMat c_image = _image.getMat(), c_mask = _mask.getMat();

cvFloodFill(&c_image, seedPoint, newVal,loDiff, upDiff, &ccomp, flags, c_mask.data.ptr ? &c_mask : 0);

if( rect )

*rect = ccomp.rect;

return cvRound(ccomp.area);

}

我们依然可以发现,其内部实现是基于OpenCV 1.X旧版的cvFloodFill函数,我们再来看看其旧版函数的源码。

5.2 OpenCV2.X中cvFloodFill()函数的实现源码

CV_IMPL void

cvFloodFill( CvArr* arr, CvPointseed_point,

CvScalar newVal, CvScalar lo_diff, CvScalar up_diff,

CvConnectedComp* comp, int flags, CvArr* maskarr )

{

cv::Ptr tempMask;

std::vector buffer;

if( comp )

memset( comp, 0, sizeof(*comp) );

int i, type, depth, cn, is_simple;

int buffer_size, connectivity = flags & 255;

union {

uchar b[4];

int i[4];

float f[4];

double _[4];

}nv_buf;

nv_buf._[0] = nv_buf._[1] = nv_buf._[2] = nv_buf._[3] = 0;

struct { cv::Vec3b b; cv::Vec3i i; cv::Vec3f f; } ld_buf, ud_buf;

CvMat stub, *img = cvGetMat(arr, &stub);

CvMat maskstub, *mask = (CvMat*)maskarr;

CvSize size;

type = CV_MAT_TYPE( img->type );

depth = CV_MAT_DEPTH(type);

cn = CV_MAT_CN(type);

if( connectivity == 0 )

connectivity = 4;

else if( connectivity != 4 && connectivity != 8 )

CV_Error( CV_StsBadFlag, "Connectivity must be 4, 0(=4) or 8");

is_simple = mask == 0 && (flags & CV_FLOODFILL_MASK_ONLY) ==0;

for( i = 0; i < cn; i++ )

{

if( lo_diff.val[i] < 0 || up_diff.val[i] < 0 )

CV_Error( CV_StsBadArg, "lo_diff and up_diff must benon-negative" );

is_simple &= fabs(lo_diff.val[i]) < DBL_EPSILON &&fabs(up_diff.val[i]) < DBL_EPSILON;

}

size = cvGetMatSize( img );

if( (unsigned)seed_point.x >= (unsigned)size.width ||

(unsigned)seed_point.y >=(unsigned)size.height )

CV_Error( CV_StsOutOfRange, "Seed point is outside of image");

cvScalarToRawData( &newVal, &nv_buf, type, 0 );

buffer_size = MAX( size.width, size.height ) * 2;

buffer.resize( buffer_size );

if( is_simple )

{

int elem_size = CV_ELEM_SIZE(type);

const uchar* seed_ptr = img->data.ptr + img->step*seed_point.y +elem_size*seed_point.x;

for(i = 0; i < elem_size; i++)

if (seed_ptr[i] != nv_buf.b[i])

break;

if (i != elem_size)

{

if( type == CV_8UC1 )

icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point,nv_buf.b[0],

comp, flags, &buffer);

else if( type == CV_8UC3 )

icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point,cv::Vec3b(nv_buf.b),

comp, flags,&buffer);

else if( type == CV_32SC1 )

icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point,nv_buf.i[0],

comp, flags,&buffer);

else if( type == CV_32FC1 )

icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point,nv_buf.f[0],

comp, flags,&buffer);

else if( type == CV_32SC3 )

icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point,cv::Vec3i(nv_buf.i),

comp, flags, &buffer);

else if( type == CV_32FC3 )

icvFloodFill_CnIR(img->data.ptr, img->step, size, seed_point,cv::Vec3f(nv_buf.f),

comp, flags,&buffer);

else

CV_Error(CV_StsUnsupportedFormat, "" );

return;

}

}

if( !mask )

{

/* created mask will be 8-byte aligned */

tempMask = cvCreateMat( size.height + 2, (size.width + 9) & -8,CV_8UC1 );

mask = tempMask;

}

else

{

mask = cvGetMat( mask, &maskstub );

if( !CV_IS_MASK_ARR( mask ))

CV_Error( CV_StsBadMask, "" );

if( mask->width != size.width + 2 || mask->height != size.height +2 )

CV_Error( CV_StsUnmatchedSizes, "mask must be 2 pixel wider "

"and 2pixel taller than filled image" );

}

int width = tempMask ? mask->step : size.width + 2;

uchar* mask_row = mask->data.ptr + mask->step;

memset(mask_row - mask->step, 1, width );

for( i = 1; i <= size.height; i++, mask_row += mask->step )

{

if( tempMask )

memset( mask_row, 0, width );

mask_row[0] = mask_row[size.width+1] = (uchar)1;

}

memset( mask_row, 1, width );

if( depth == CV_8U )

for( i = 0; i < cn; i++ )

{

int t = cvFloor(lo_diff.val[i]);

ld_buf.b[i] = CV_CAST_8U(t);

t = cvFloor(up_diff.val[i]);

ud_buf.b[i] = CV_CAST_8U(t);

}

else if( depth == CV_32S )

for( i = 0; i < cn; i++ )

{

int t = cvFloor(lo_diff.val[i]);

ld_buf.i[i] = t;

t = cvFloor(up_diff.val[i]);

ud_buf.i[i] = t;

}

else if( depth == CV_32F )

for( i = 0; i < cn; i++ )

{

ld_buf.f[i] = (float)lo_diff.val[i];

ud_buf.f[i] = (float)up_diff.val[i];

}

else

CV_Error( CV_StsUnsupportedFormat, "" );

if( type == CV_8UC1 )

icvFloodFillGrad_CnIR(

img->data.ptr,img->step, mask->data.ptr, mask->step,

size, seed_point,nv_buf.b[0],

Diff8uC1(ld_buf.b[0],ud_buf.b[0]),

comp, flags,&buffer);

else if( type == CV_8UC3 )

icvFloodFillGrad_CnIR<:vec3b cv::vec3i diff8uc3>(

img->data.ptr,img->step, mask->data.ptr, mask->step,

size, seed_point,cv::Vec3b(nv_buf.b),

Diff8uC3(ld_buf.b, ud_buf.b),

comp, flags,&buffer);

else if( type == CV_32SC1 )

icvFloodFillGrad_CnIR(

img->data.ptr,img->step, mask->data.ptr, mask->step,

size, seed_point,nv_buf.i[0],

Diff32sC1(ld_buf.i[0], ud_buf.i[0]),

comp, flags, &buffer);

else if( type == CV_32SC3 )

icvFloodFillGrad_CnIR<:vec3i cv::vec3i diff32sc3>(

img->data.ptr,img->step, mask->data.ptr, mask->step,

size, seed_point,cv::Vec3i(nv_buf.i),

Diff32sC3(ld_buf.i, ud_buf.i),

comp, flags,&buffer);

else if( type == CV_32FC1 )

icvFloodFillGrad_CnIR(

img->data.ptr,img->step, mask->data.ptr, mask->step,

size, seed_point,nv_buf.f[0],

Diff32fC1(ld_buf.f[0], ud_buf.f[0]),

comp, flags,&buffer);

else if( type == CV_32FC3 )

icvFloodFillGrad_CnIR<:vec3f cv::vec3f diff32fc3>(

img->data.ptr,img->step, mask->data.ptr, mask->step,

size, seed_point,cv::Vec3f(nv_buf.f),

Diff32fC3(ld_buf.f,ud_buf.f),

comp, flags,&buffer);

else

CV_Error(CV_StsUnsupportedFormat, "");

}

四、关于SetMouseCallback函数

因为下面示例程序中有用到SetMouseCallback函数,我们在这里讲一讲。SetMouseCallback函数为指定的窗口设置鼠标回调函数。

C++: void setMouseCallback(conststring& winname, MouseCallback onMouse, void* userdata=0 )

第一个参数,const string&类型的winname,为窗口的名字。第二个参数,MouseCallback类型的onMouse,指定窗口里每次鼠标时间发生的时候,被调用的函数指针。这个函数的原型应该为voidFoo(int event, int x, int y, int flags, void* param);其中event是 CV_EVENT_*变量之一, x和y是鼠标指针在图像坐标系的坐标(不是窗口坐标系), flags是CV_EVENT_FLAG的组合, param是用户定义的传递到cvSetMouseCallback函数调用的参数。第三个参数,void*类型的userdata,用户定义的传递到回调函数的参数,有默认值0。

五、综合示例部分

本次的综合示例为OpenCV文档中自带的一个程序。浅墨将其做了适当的修改并详细注释,放出来供大家消化理解。

操作说明如下:

a71276c3a649f56e3a364d422d84dc98.png

可以看到,此程序着不少的按键功能。而我们拿着鼠标对窗口中的图形一顿狂点,就可以得到类似PhotoShop中魔棒的效果,当然,就这短短的两百来行代码写出来的东西,体验是比不上PS的魔棒工具的。

废话不多说,程序详细注释的源码如下:

//-----------------------------------【程序说明】----------------------------------------------

//程序名称::《【OpenCV入门教程之十五】水漫金山:OpenCV漫水填充算法(Floodfill)》 博文配套源码

//开发所用IDE版本:Visual Studio 2010

// 开发所用OpenCV版本:2.4.9

//2014年6月3日 Created by 浅墨

//浅墨的微博:@浅墨_毛星云 http://weibo.com/1723155442/profile?topnav=1&wvr=5&user=1

//浅墨的知乎:http://www.zhihu.com/people/mao-xing-yun

//浅墨的豆瓣:http://www.douban.com/people/53426472/

//----------------------------------------------------------------------------------------------

//-----------------------------------【头文件包含部分】---------------------------------------

// 描述:包含程序所依赖的头文件

//----------------------------------------------------------------------------------------------

#include "opencv2/imgproc/imgproc.hpp"

#include "opencv2/highgui/highgui.hpp"

#include

//-----------------------------------【命名空间声明部分】---------------------------------------

// 描述:包含程序所使用的命名空间

//-----------------------------------------------------------------------------------------------

using namespace cv;

using namespace std;

//-----------------------------------【全局变量声明部分】--------------------------------------

// 描述:全局变量声明

//-----------------------------------------------------------------------------------------------

Mat g_srcImage, g_dstImage, g_grayImage, g_maskImage;//定义原始图、目标图、灰度图、掩模图

int g_nFillMode = 1;//漫水填充的模式

int g_nLowDifference = 20, g_nUpDifference = 20;//负差最大值、正差最大值

int g_nConnectivity = 4;//表示floodFill函数标识符低八位的连通值

int g_bIsColor = true;//是否为彩色图的标识符布尔值

bool g_bUseMask = false;//是否显示掩膜窗口的布尔值

int g_nNewMaskVal = 255;//新的重新绘制的像素值

//-----------------------------------【ShowHelpText( )函数】----------------------------------

// 描述:输出一些帮助信息

//----------------------------------------------------------------------------------------------

static void ShowHelpText()

{

//输出一些帮助信息

printf("

欢迎来到漫水填充示例程序~

");

printf( "

按键操作说明:

"

"鼠标点击图中区域- 进行漫水填充操作

"

"键盘按键【ESC】- 退出程序

"

"键盘按键【1】- 切换彩色图/灰度图模式

"

"键盘按键【2】- 显示/隐藏掩膜窗口

"

"键盘按键【3】- 恢复原始图像

"

"键盘按键【4】- 使用空范围的漫水填充

"

"键盘按键【5】- 使用渐变、固定范围的漫水填充

"

"键盘按键【6】- 使用渐变、浮动范围的漫水填充

"

"键盘按键【7】- 操作标志符的低八位使用4位的连接模式

"

"键盘按键【8】- 操作标志符的低八位使用8位的连接模式

"

"

by浅墨

"

);

}

//-----------------------------------【onMouse( )函数】--------------------------------------

// 描述:鼠标消息onMouse回调函数

//---------------------------------------------------------------------------------------------

static void onMouse( int event, int x, int y, int, void* )

{

// 若鼠标左键没有按下,便返回

if( event != CV_EVENT_LBUTTONDOWN )

return;

//-------------------【<1>调用floodFill函数之前的参数准备部分】---------------

Point seed = Point(x,y);

int LowDifference = g_nFillMode == 0 ? 0 : g_nLowDifference;//空范围的漫水填充,此值设为0,否则设为全局的g_nLowDifference

int UpDifference = g_nFillMode == 0 ? 0 : g_nUpDifference;//空范围的漫水填充,此值设为0,否则设为全局的g_nUpDifference

int flags = g_nConnectivity + (g_nNewMaskVal << 8) +

(g_nFillMode == 1 ? CV_FLOODFILL_FIXED_RANGE : 0);//标识符的0~7位为g_nConnectivity,8~15位为g_nNewMaskVal左移8位的值,16~23位为CV_FLOODFILL_FIXED_RANGE或者0。

//随机生成bgr值

int b = (unsigned)theRNG() & 255;//随机返回一个0~255之间的值

int g = (unsigned)theRNG() & 255;//随机返回一个0~255之间的值

int r = (unsigned)theRNG() & 255;//随机返回一个0~255之间的值

Rect ccomp;//定义重绘区域的最小边界矩形区域

Scalar newVal = g_bIsColor ? Scalar(b, g, r) : Scalar(r*0.299 + g*0.587 + b*0.114);//在重绘区域像素的新值,若是彩色图模式,取Scalar(b, g, r);若是灰度图模式,取Scalar(r*0.299 + g*0.587 + b*0.114)

Mat dst = g_bIsColor ? g_dstImage : g_grayImage;//目标图的赋值

int area;

//--------------------【<2>正式调用floodFill函数】-----------------------------

if( g_bUseMask )

{

threshold(g_maskImage, g_maskImage, 1, 128, CV_THRESH_BINARY);

area = floodFill(dst, g_maskImage, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),

Scalar(UpDifference, UpDifference, UpDifference), flags);

imshow( "mask", g_maskImage );

}

else

{

area = floodFill(dst, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),

Scalar(UpDifference, UpDifference, UpDifference), flags);

}

imshow("效果图", dst);

cout << area << " 个像素被重绘

";

}

//-----------------------------------【main( )函数】--------------------------------------------

// 描述:控制台应用程序的入口函数,我们的程序从这里开始

//-----------------------------------------------------------------------------------------------

int main( int argc, char** argv )

{

//改变console字体颜色

system("color 2F");

//载入原图

g_srcImage = imread("1.jpg", 1);

if( !g_srcImage.data ) { printf("Oh,no,读取图片image0错误~!

"); return false; }

//显示帮助文字

ShowHelpText();

g_srcImage.copyTo(g_dstImage);//拷贝源图到目标图

cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);//转换三通道的image0到灰度图

g_maskImage.create(g_srcImage.rows+2, g_srcImage.cols+2, CV_8UC1);//利用image0的尺寸来初始化掩膜mask

namedWindow( "效果图",CV_WINDOW_AUTOSIZE );

//创建Trackbar

createTrackbar( "负差最大值", "效果图", &g_nLowDifference, 255, 0 );

createTrackbar( "正差最大值" ,"效果图", &g_nUpDifference, 255, 0 );

//鼠标回调函数

setMouseCallback( "效果图", onMouse, 0 );

//循环轮询按键

while(1)

{

//先显示效果图

imshow("效果图", g_bIsColor ? g_dstImage : g_grayImage);

//获取键盘按键

int c = waitKey(0);

//判断ESC是否按下,若按下便退出

if( (c & 255) == 27 )

{

cout << "程序退出...........

";

break;

}

//根据按键的不同,进行各种操作

switch( (char)c )

{

//如果键盘“1”被按下,效果图在在灰度图,彩色图之间互换

case '1':

if( g_bIsColor )//若原来为彩色,转为灰度图,并且将掩膜mask所有元素设置为0

{

cout << "键盘“1”被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】

";

cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);

g_maskImage = Scalar::all(0);//将mask所有元素设置为0

g_bIsColor = false;//将标识符置为false,表示当前图像不为彩色,而是灰度

}

else//若原来为灰度图,便将原来的彩图image0再次拷贝给image,并且将掩膜mask所有元素设置为0

{

cout << "键盘“1”被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】

";

g_srcImage.copyTo(g_dstImage);

g_maskImage = Scalar::all(0);

g_bIsColor = true;//将标识符置为true,表示当前图像模式为彩色

}

break;

//如果键盘按键“2”被按下,显示/隐藏掩膜窗口

case '2':

if( g_bUseMask )

{

destroyWindow( "mask" );

g_bUseMask = false;

}

else

{

namedWindow( "mask", 0 );

g_maskImage = Scalar::all(0);

imshow("mask", g_maskImage);

g_bUseMask = true;

}

break;

//如果键盘按键“3”被按下,恢复原始图像

case '3':

cout << "按键“3”被按下,恢复原始图像

";

g_srcImage.copyTo(g_dstImage);

cvtColor(g_dstImage, g_grayImage, COLOR_BGR2GRAY);

g_maskImage = Scalar::all(0);

break;

//如果键盘按键“4”被按下,使用空范围的漫水填充

case '4':

cout << "按键“4”被按下,使用空范围的漫水填充

";

g_nFillMode = 0;

break;

//如果键盘按键“5”被按下,使用渐变、固定范围的漫水填充

case '5':

cout << "按键“5”被按下,使用渐变、固定范围的漫水填充

";

g_nFillMode = 1;

break;

//如果键盘按键“6”被按下,使用渐变、浮动范围的漫水填充

case '6':

cout << "按键“6”被按下,使用渐变、浮动范围的漫水填充

";

g_nFillMode = 2;

break;

//如果键盘按键“7”被按下,操作标志符的低八位使用4位的连接模式

case '7':

cout << "按键“7”被按下,操作标志符的低八位使用4位的连接模式

";

g_nConnectivity = 4;

break;

//如果键盘按键“8”被按下,操作标志符的低八位使用8位的连接模式

case '8':

cout << "按键“8”被按下,操作标志符的低八位使用8位的连接模式

";

g_nConnectivity = 8;

break;

}

}

return 0;

}

一些运行截图,首先是运行后的原始图:

438dd125393fb4ae0da97c6ee3086abb.png

点鼠标啊点鼠标:

bee6c2b6eded6df0f54d01e27fa1dba4.png

滑滚动条啊滑滚动条:

a0c1494c60ee22f60c24668652a9d38d.png

地球已经阻止不了我们的鼠标了,点出来的图,已经有点恐怖。。。。。看妹子的手。。。。

3d9187c6024c8ba5b3d725c44945f75a.png

如果鼠标点到妹子脸上的话。。。。呃,更多惊悚的图,浅墨不放出了,免得。。。。。

随着我们鼠标的点击,程序会记下我们的操作:

3e8eeee83b18714b5e0dbb67d54b7b79.png

接着看一张灰度图模式的漫水填充效果和掩码图:

dc22ffaaf2e51197cfe928bc5692577c.png

再来一张彩色窗户:

37d76db0acd213825494ee0d973b2a98.png

程序功能还是很多的,有鼠标操作,键盘8个按键的操作,还可以调滚动条:

099b1ab0b73c7e100634968a7e313bbb.png

好了,更多的功能我们就不在这里示范了,大家下载了程序自己回去玩吧。

本篇文章的配套源代码请点击这里下载:

【浅墨OpenCV入门教程之十五】配套源代码下载

这篇关于c语言floodfill算法,OpenCV入门教程之十五水漫金山:OpenCV漫水填充算法(Floodfill)...的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/763193

相关文章

Rust中的Option枚举快速入门教程

《Rust中的Option枚举快速入门教程》Rust中的Option枚举用于表示可能不存在的值,提供了多种方法来处理这些值,避免了空指针异常,文章介绍了Option的定义、常见方法、使用场景以及注意事... 目录引言Option介绍Option的常见方法Option使用场景场景一:函数返回可能不存在的值场景

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

opencv实现像素统计的示例代码

《opencv实现像素统计的示例代码》本文介绍了OpenCV中统计图像像素信息的常用方法和函数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 统计像素值的基本信息2. 统计像素值的直方图3. 统计像素值的总和4. 统计非零像素的数量

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO