保边滤波之Mean shift filter

article/2025/11/6 16:32:16

                          Mean shift filter

目录

                          Mean shift filter

一、算法原理

二、练手实现的算法代码如下:

三、实现结果




一、算法原理

在OpenCV中,meanshift filter函数为 pyrMeanShiftFiltering, 它的函数调用格式如下:

C++: void pyrMeanShiftFiltering(InputArray src, OutputArray dst, double sp, double sr, int maxLevel=1, TermCriteriatermcrit=TermCriteria( TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) )

Parameters:

  • src – The source 8-bit, 3-channel image. //三通道的输入图像
  • dst – The destination image of the same format and the same size as the source. //相同尺寸格式输出图像
  • sp – The spatial window radius.  //空间域半径
  • sr – The color window radius.  //颜色域半径
  • maxLevel – Maximum level of the pyramid for the segmentation. //分割用金字塔的最大层数
  • termcrit – Termination criteria: when to stop meanshift iterations. //迭代终止的条件

算法的描述大致如下:

对于输入图像的每个像素点(X,Y) ,在它的半径为sp的空间域,执行meanshift迭代算法,

像素点(X,Y)的颜色值为(R,G,B), 它的空间邻域点(x,y)的颜色值为(r,g,b),如果点(x,y)的到(X,Y)的颜色距离小于sr,则满足条件,最终我们求得满足条件点的平均空间坐标(X’,Y’)以及平均颜色向量(R',G',B'),并把它们作为下一次迭代的输入。

迭代结果后,我们把最初输入位置的颜色值用最终迭代的颜色值代替。

 

二、练手实现的算法代码如下:

#include"cv.h"
#include"highgui.h"
#include"cxcore.h"
#include<stdio.h>
#include<stdlib.h>
#include"types.h"void ToYIQ(IplImage *img,IplImage *YIQ_img)
{int i,j;float Y,I,Q;uchar R,G,B;for(i = 0 ;i < img->height;i++){for(j = 0; j < img->width;j++){B = ((uchar*)(img->imageData+i*img->widthStep))[j*img->nChannels+0];G = ((uchar*)(img->imageData+i*img->widthStep))[j*img->nChannels+1];R = ((uchar*)(img->imageData+i*img->widthStep))[j*img->nChannels+2];Y = 0.299*R +0.587*G +0.114*B;I = 0.5957*R-0.2744*G-0.3212*B;Q = 0.2114*R-0.5226*G+0.3111*B;((float*)(YIQ_img->imageData+i*YIQ_img->widthStep))[j*YIQ_img->nChannels+0] = Y;((float*)(YIQ_img->imageData+i*YIQ_img->widthStep))[j*YIQ_img->nChannels+1] = I;((float*)(YIQ_img->imageData+i*YIQ_img->widthStep))[j*YIQ_img->nChannels+2] = Q;}}
}void Mean_Shift_Filter(IplImage *img, IplImage *YIQ_img, IplImage *mean_shift_img,int rad,int colordis )
{float shift,Yc,Ic,Qc,YcOld,IcOld,QcOld,Y2,I2,Q2,dY,dI,dQ,mY,mI,mQ,num_;int i,j,ry,rx,y2,x2,xc,yc,xcOld,ycOld,num,dx,dy,iters,mx,my;uchar R,G,B;shift  = 0;iters  = 0;for(i = 0; i < img->height;i++){for(j = 0; j < img->width;j++){yc = i;xc = j;Yc = ((float*)(YIQ_img->imageData+yc*YIQ_img->widthStep))[xc*YIQ_img->nChannels+0];Ic = ((float*)(YIQ_img->imageData+yc*YIQ_img->widthStep))[xc*YIQ_img->nChannels+1];Qc = ((float*)(YIQ_img->imageData+yc*YIQ_img->widthStep))[xc*YIQ_img->nChannels+2];iters = 0;do{ycOld = yc;xcOld = xc;YcOld = Yc;IcOld = Ic;QcOld = Qc;mx = 0;my = 0;mY = 0;mI = 0;mQ = 0;num = 0;
/*///
假若是rad= 3,则其邻域范围为:其中#为包含在内需要计算的像素点***#*****###***#####*#######*#####***###*****#***
///*/for(ry = - rad;ry <= rad;ry++){y2 = yc+ry;if(y2 >= 0 && y2 < img->height){for(rx = -rad;rx <= rad;rx++){x2 = xc+rx;if(x2 >= 0 && x2 < img->width){if(ry*ry+rx*rx <= rad*rad){Y2 = ((float*)(YIQ_img->imageData+y2*YIQ_img->widthStep))[x2*YIQ_img->nChannels+0];I2 = ((float*)(YIQ_img->imageData+y2*YIQ_img->widthStep))[x2*YIQ_img->nChannels+1];Q2 = ((float*)(YIQ_img->imageData+y2*YIQ_img->widthStep))[x2*YIQ_img->nChannels+2];dY = Yc-Y2;dI = Ic- I2;dQ = Qc- Q2;if(dY*dY + dI*dI+dQ*dQ <= colordis)//当前像素比周围邻域像素相差比较大的时候,在rad半径内(一个菱形领域),只有当前像素满足此条件,所以最后替换当前像素还是自己本身{mx += x2;my += y2;mY += Y2;mI += I2;mQ += Q2;num++;}}}}}}num_ = 1.0/num;Yc = mY*num_;Ic = mI*num_;Qc = mQ*num_;xc = (int)(mx*num_+0.5);yc = (int)(my*num_+0.5);dx = xc - xcOld;dy = yc -ycOld;dY = Yc - YcOld;dI = Ic- IcOld;dQ = Qc - QcOld;shift = dx*dx+dy*dy+dY*dY+dI*dI+dQ*dQ;iters++;}while(shift> 3 && iters < 100);R = CLIP((int)(Yc+0.9653*Ic+0.6210*Qc),0,255);G = CLIP((int)(Yc-0.2721*Ic-0.6473*Qc),0,255);B = CLIP((int)(Yc-1.1070*Ic+1.7046*Qc),0,255);((uchar*)(mean_shift_img->imageData+i*mean_shift_img->widthStep))[j*mean_shift_img->nChannels+0] = B;((uchar*)(mean_shift_img->imageData+i*mean_shift_img->widthStep))[j*mean_shift_img->nChannels+1] = G;((uchar*)(mean_shift_img->imageData+i*mean_shift_img->widthStep))[j*mean_shift_img->nChannels+2] = R;	}}}
int main(void)
{int w,h;CvSize img_size;IplImage *src,*mean_shift_img,*YIQ_img;src = cvLoadImage("lg-image4.bmp",-1);if(src == NULL){printf("Please insert image\n");return 0;}img_size = cvGetSize(src);w = img_size.width;h = img_size.height;YIQ_img = cvCreateImage(img_size,IPL_DEPTH_32F,3);mean_shift_img = cvCreateImage(img_size,IPL_DEPTH_8U,3);if((mean_shift_img == NULL) || (YIQ_img==NULL))printf("malloc for image memory failure!\n");cvZero(YIQ_img);cvZero(mean_shift_img);cvNamedWindow("Show original image",0);cvShowImage("Show original image",src);ToYIQ(src,YIQ_img);Mean_Shift_Filter(src, YIQ_img, mean_shift_img,5,15*15 );cvNamedWindow("Mean Shift image",0);cvShowImage("Mean Shift image",mean_shift_img);cvSaveImage("lg-image4_Mean_Shift_filter.bmp",mean_shift_img);cvWaitKey(0);cvDestroyWindow("Mean Shift image");cvDestroyWindow("Show original image");printf("done\n");cvReleaseImage(&YIQ_img);cvReleaseImage(&mean_shift_img);return 0;
}

三、实现结果

左侧为原始图像;右侧为结果图像
标题左侧为原始图像;右侧为结果图像

 

但是针对椒盐噪声,其效果基本无效:

左侧为原始图像;右侧为添加椒盐噪声图像

 

左侧为原始图像mean_shift filter之后结果;右侧为添加椒盐噪声图像mean_shift_filter处理结果

 


http://chatgpt.dhexx.cn/article/dSmlcWmO.shtml

相关文章

mean shift

参考&#xff1a; http://blog.csdn.net/google19890102/article/details/51030884 http://www.cvvision.cn/5778.html https://wenku.baidu.com/view/5862334827d3240c8447ef40.html http://blog.csdn.net/qq_23968185/article/details/51804574 https://www.cnblogs.com…

机器学习算法原理与实践(二)、meanshift算法图解以及在图像聚类、目标跟踪中的应用

【原创】Liu_LongPo 转载请注明出处 【CSDN】http://blog.csdn.net/llp1992 最近在关注跟踪这一块的算法&#xff0c;对于meanshift的了解也是来自论文和博客&#xff0c;本博客将对meanshift算法进行总结&#xff0c;包括meanshift算法原理以及公式推导&#xff0c;图解&…

基于MeanShift的目标跟踪算法及实现

这次将介绍基于MeanShift的目标跟踪算法&#xff0c;首先谈谈简介&#xff0c;然后给出算法实现流程&#xff0c;最后实现了一个单目标跟踪的MeanShift算法【matlab/c两个版本】 csdn贴公式比较烦&#xff0c;原谅我直接截图了… 一、简介 首先扯扯无参密度估计理论&#xff0c…

聚类算法:Mean Shift

目录 简介 mean shift 算法理论 Mean Shift算法原理 算法步骤 算法实现 其他 聚类算法之Mean Shift Mean Shift算法理论 Mean Shift向量 核函数 引入核函数的Mean Shift向量 聚类动画演示 Mean Shift的代码实现 算法的Python实现 scikit-learn MeanShift演示 s…

meanshift算法通俗讲解

这几天学习《学习OpenCV》中的第十章运动跟踪&#xff0c;里面讲到了meanshift算法&#xff0c;根据书上所讲实在难以理解&#xff0c;meanshift在运动跟踪这个过程中到底起到什么作用&#xff0c;于是经过几天不断地看相关资料和别人的博客文章&#xff0c;慢慢思路清晰了&…

机器学习实验 - MeanShift聚类

目录 一、报告摘要1.1 实验要求1.2 实验思路1.3 实验结论 二、实验内容2.1 方法介绍2.2 实验细节2.2.1 实验环境2.2.2 实验过程2.2.3 实验与理论内容的不同点 2.3 实验数据介绍2.4 评价指标介绍2.5 实验结果分析 三、总结及问题说明四、参考文献附录&#xff1a;实验代码 报告内…

聚类 之 MeanShift

文章目录 Meanshift 聚类基本原理Meanshift 聚类流程简述实例演示MeanShift聚类简易应用示例总结拓展阅读 上篇博客介绍了基于距离的K-Means聚类&#xff0c;这次给大家推荐一个基于密度的聚类算法&#xff1a;Meanshift&#xff08;均值漂移&#xff09;。 Meanshift 聚类基本…

Muduo源码剖析

1、总体流程 1. acceptor 进行listen阶段后&#xff0c; 往channel中注册可读事件。 2. acceptor可读处理中生成TcpConnection指针&#xff0c;通过EventloopThreadPool 轮询出其中一个线程的eventloop, 并将此TcpConnection的可读、可写等事件注册到自己Channel&#xff08;ev…

Muduo - Reactor模式

Muduo - Reactor模式 一、Reactor 是什么 wiki的中文定义&#xff1a;Reactor模式是事件驱动的&#xff0c;有一个或多个并发输入源&#xff0c;有一个Service Handler&#xff0c;有多个Request Handler&#xff0c;这个Service Handler会同步的将输入的请求&#xff08;Even…

muduo网络库——ThreadPool

模型 源码分析 1&#xff09;接口 class ThreadPool : noncopyable {public:typedef std::function<void ()> Task;explicit ThreadPool(const string& nameArg string("ThreadPool"));~ThreadPool();void setMaxQueueSize(int maxSize) { maxQueueSize…

muduo网络库——Channel

模型 实现流程&#xff1a; 前面已经介绍了EPoller类&#xff0c;EPoller主要监听的是Channel对象&#xff0c;每一个Channel对象会绑定一个文件描述符&#xff08;fd_&#xff09;&#xff0c;fd_上绑定要监听的事件。当epoll监听到就绪事件时&#xff0c;会将就绪事件添加到…

muduo源码分析之Buffer

这一次我们来分析下muduo中Buffer的作用&#xff0c;我们知道&#xff0c;当我们客户端向服务器发送数据时候&#xff0c;服务器就会读取我们发送的数据&#xff0c;然后进行一系列处理&#xff0c;然后再发送到其他地方&#xff0c;在这里我们想象一下最简单的EchoServer服务器…

从实例看muduo网络库各模块交互过程

文章目录 muduo网络库的核心代码模块各模块功能解释ChannelPollerEpollPoller EventLoopEventLoopThreadEventLoopThreadPoolTcpServerTcpConnection 从实际应用出发 muduo网络库的核心代码模块 1、channel 2、Poller 和它的子类 EpollPoller 3、EventLoop 4、Thread、EventLo…

muduo总结

本文重点在muduo TcpServer的启动&#xff0c;I/O线程池的启动&#xff0c;以及各种回调 文章目录 baseAsyncLogging.{h,cc}Atomic.hBlockinQueue.hBoundedBlockinQueue.hCondition.hcopyable.hCountDownLatch.{h,cc}Date.{h,cc}Exception.{h,cc}Logging.{h,cc}Mutex.hProcess…

muduo网络库——日志处理

测试程序 #include "muduo/base/AsyncLogging.h" #include "muduo/base/Logging.h" #include "muduo/base/Timestamp.h"#include <stdio.h> #include <sys/resource.h> #include <unistd.h>off_t kRollSize 500*1000*1000;m…

Muduo日志模块详解

Muduo日志模块解析 图片取自muduo网络库源码解析(1):多线程异步日志库(上)_李兆龙的技术博客_51CTO博客也是很好的日志讲解博客,这篇讲解流程基本上和它差不多,并且写的比我条理清楚很多 AppendFile::append() 这个函数是日志写入文件的最终函数,并且AppendFile这个类里面也是…

Muduo 定时器

TimeQueue定时器 图片转载自:muduo网络库源码解析(4):TimerQueue定时机制_李兆龙的技术博客_51CTO博客 添加新的定时器 TimerId TimerQueue::addTimer(TimerCallback cb, //用户自定义回调Timestamp when, //定时器的超时时刻double interval) //重复触发间隔,小于0则不重…

《muduo网络库》学习笔记——muduo学习总结

muduo是基于非阻塞的IO和事件驱动的网络库&#xff08;Reactor模式&#xff09;&#xff0c;其核心是一个事件循环EventLoop&#xff0c;用于响应计时器和IO事件。muduo采用基于对象&#xff08;object-based&#xff09;而非面向对象&#xff08;object-oriented&#xff09;的…

Ubuntu安装muduo库

1. 首先安装boost库&#xff1b; sudo apt-get update sudo apt-get install libboost-all-dev 2. 下载muduo库&#xff0c; https://github.com/chenshuo/muduo 3. 解压后进入解压目录&#xff0c;vim CMakeLists.txt&#xff0c;注释掉略过unit_test测试用例代码的编译&#…

linux muduo 编译安装,muduo记录

1.muduo编译安装 编译muduo遇见的报错可以在github上的issue上面查找。一般都能顺利解决,我遇到的就是没有安装boost-dev. centos7系统 执行: sudo yum install boost-dev 2.截取流程图 图片截取自《Linux多线程服务端编程&#xff1a;使用muduo C网络库》 3.源码摘录 摘录一个…