斜率DP十连测


最近学校里很多题目都没时间做,顺便来写一下博客
斜率DP十连:

A[征途]
注意到,原题的式子,等价于ma2i(ai)2m∑ai2−(∑ai)2后面部分是常数
那么我们就可以写出dp方程f[i,j]=min{f[i1,k]+(sjsk)2},k<jf[i,j]=min{f[i−1,k]+(sj−sk)2},k<j
对每个i单独做斜率dp,那么式子改写为fi=min{2sjsi+fj+s2j+s2i}fi=min{−2sjsi+fj+sj2+si2}
斜率为sisi,维护下凸包即可

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define LL long long 
using namespace std;
int n,m,q[3010],T; LL f[2][3010],s[3010];
inline LL y(int j){
    return f[T^1][j]+s[j]*s[j];
}
inline db slp(int j,int k){
    return (y(j)-y(k))/(db)(2.*(s[j]-s[k])); 
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) scanf("%lld",s+i),s[i]+=s[i-1];
    for(int i=1;i<=m;++i){
        int l=0,r=0; T=i&1;
        for(int j=1;j<=n;++j){
            while(l<r && slp(q[l],q[l+1])<s[j]) ++l; int k=q[l];
            f[T][j]=y(k)+s[j]*s[j]-2*s[j]*s[k]; 
            while(l<r && slp(q[r-1],q[r])>slp(q[r],j)) --r;
            q[++r]=j;
        }
    }
    printf("%lld\n",m*f[m&1][n]-s[n]*s[n]);
}




B[货币兑换]
是一个神仙题也
首先注意到一个贪心策略,每天要么全部买入,全部卖出或者什么也不做
好的,注意到这一点之后就可以考虑怎么dp了,设fifi表示到了第i天最多有多少钱
xixi表示到了第i天最多有多少a股,yiyi表示同时最多有多少b股
我们有三种转移
1.今天什么也不做fi=fi1fi=fi−1
2.今天卖掉从某一天买来的股票fi=max{aixj+biyj},j<ifi=max{ai∗xj+bi∗yj},j<i
3.买入股票yi=fiairatei+bi,xi=yirateiyi=fiai∗ratei+bi,xi=yi∗ratei
重点关注第二条式子,我们将其改写:

yj=aibixj+fibiyj=−aibi∗xj+fibi

这里b是常数可以不管,只需要维护上凸包,让后在凸包上二分斜率aibi−aibi即可
但是发现aibi−aibi不是单调的,我们需要选择以下一项:
1.splay维护凸包
2.cdq分治
前者明显比后者直观易懂,所以我们用splay维护凸包,过程和用队列差不多,只是如果一个点被加入到了凸包内部需要直接删除,而加入的有用的点,直接找它左边和右边第一个满足上凸的点,并将中间的都删掉即可

#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100010
#define db double
#define eps 1e-9
#define inf 1e9
#define son(x) (s[f[x]][1]==x)
using namespace std;
int n,s[N][2],v[N],f[N],rt;
db l[N],r[N],a[N],b[N],X[N],Y[N],g[N],rat[N];
inline db slp(int j,int k){
    return fabs(X[j]-X[k])<eps?-inf:(Y[j]-Y[k])/(double)(X[j]-X[k]);
}
inline void rot(int x){
    int y=f[x],d=son(x),g=f[y];
    s[y][d]=s[x][!d]; f[s[y][d]]=y;
    if(g) s[g][son(y)]=x; f[x]=g;
    s[x][!d]=y; f[y]=x;
}
inline void splay(int x,int r=0){
    for(int p;(p=f[x])!=r;rot(x))
        if(f[p]!=r && son(x)==son(p)) rot(p);
    if(!r) rt=x;
}
inline void insert(int k){
    if(!rt){ rt=k; return; }
    for(int x=rt;;){
        int d=X[x]<X[k];
        if(!s[x][d]){ s[x][d]=k; f[k]=x; splay(k); return; }
        else x=s[x][d];
    }
}
inline int gPre(int k){
    int r=0;
    for(int x=s[k][0];x;){
        if(slp(x,k)<=l[x]+eps) r=x,x=s[x][1];
        else x=s[x][0];
    }
    return r;
}
inline int gSuc(int k){
    int l=0;
    for(int x=s[k][1];x;){
        if(slp(x,k)+eps>=r[x]) l=x,x=s[x][0];
        else x=s[x][1];
    }
    return l;
}
inline void ps(int k){
    int p;
    if(s[k][0]){
        p=gPre(k);
        splay(p,k);
        f[s[p][1]]=0;
        s[p][1]=0;
        l[k]=r[p]=slp(k,p);
    } else l[k]=inf;
    if(s[k][1]){
        p=gSuc(k);
        splay(p,k);
        f[s[p][0]]=0;
        s[p][0]=0;
        r[k]=l[p]=slp(k,p);
    } else r[k]=-inf;
}
inline void maintain(int k){
    splay(k); ps(k); int p;
    if(l[k]<=r[k]+eps){
        if(!s[k][0] || !s[k][1]){
            rt=s[k][0]+s[k][1];
            f[rt]=0; ps(rt);
        } else {
            p=gSuc(k);
            splay(p,k);
            rt=s[k][0];
            f[rt]=0;
            s[rt][1]=p;
            f[p]=rt;
            ps(p); ps(rt);
        }
    }
}
inline void out(int x){
    if(!x) return;
    out(s[x][0]);
    printf("%d ",x);
    out(s[x][1]);
}
inline int find(db k){
    if(!rt) return 0;
    int x=rt;
    for(;;){
        if(r[x]>k+eps) x=s[x][1]; else
        if(l[x]+eps<k) x=s[x][0];
        else return x;
    }
}
int main(){
    scanf("%d%lf",&n,g);
    for(int i=1;i<=n;++i) scanf("%lf%lf%lf",a+i,b+i,rat+i);
    for(int i=1;i<=n;++i){
        int j=find(-a[i]/b[i]);
        g[i]=max(g[i-1],a[i]*X[j]+b[i]*Y[j]);
    //  printf("%d\n",j);
        Y[i]=g[i]/(a[i]*rat[i]+b[i]);
        X[i]=Y[i]*rat[i]; insert(i); maintain(i);// out(rt); puts("");
    }
    for(int i=n;i<=n;++i) printf("%.3lf\n",g[i]);
}



C[柠檬]
不得不说这题如果想到了关键一步就基本秒掉了,然而我并没有想到
首先考虑一下怎么转移式子
fifi表示前i个贝壳能转化为多少柠檬,枚举j,发现各种无法转移
因为我们不可能去枚举s0s0那怎么办呢
注意到决策最优性,如果对于某一段,我们选取大小为s0s0的贝壳去做转化,那么这一段的开头和结尾必然也是s0s0否则我们将其分成独立的一段,一定更优
这下马上可以转移了,写成方程就是

fi=max{fj1+vi(sisj+1)2},vi=vjfi=max{fj−1+vi∗(si−sj+1)2},vi=vj

这里vivi贝壳i的大小,sisi表示的是i是第几个大小为vivi的贝壳
那么对于每个v[i]我们维护一个单独的上凸壳,每次询问在上面二分即可,这里用vector节省空间

#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define LL long long 
#define db double
using namespace std;
vector<int> q[10010];
int n,c[10010],v[100010]; LL f[100010],s[100010];
inline LL y(int j){
    return f[j-1]+v[j]*s[j]*s[j]-2*s[j]*v[j];
}
inline db slp(int j,int k){
    return (y(j)-y(k))/(2.*v[j]*(s[j]-s[k]));
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d",v+i);
        s[i]=s[c[v[i]]]+1; c[v[i]]=i;
    }
//  for(int i=1;i<=n;++i){
//      for(int j=1;j<=i;++j) if(v[i]==v[j])
//          g[i]=max(g[i],g[j-1]+v[i]*(s[i]-s[j]+1)*(s[i]-s[j]+1));
//  }
//  for(int i=1;i<=n;++i) if(s[i]==1) q[v[i]].push_back(i);
    for(int i=1,j,k;i<=n;++i){
        k=v[i];
        if(q[k].size()<=1) q[k].push_back(i); else{
            for(int j=q[k].size()-1;j;--j)
                if(slp(q[k][j],q[k][j-1])<slp(q[k][j],i)) q[k].pop_back(); else break;
            q[k].push_back(i);
        }
        if(q[k].size()==1) j=q[k][0];
        else {
            int l=0,r=q[k].size()-1;
            for(int m;l<r;){
                m=l+r>>1;
                if(slp(q[k][m],q[k][m+1])>=s[i]) l=m+1;
                else r=m;
            }
            j=q[k][l];
        }
        f[i]=f[j-1]+v[i]*(s[i]-s[j]+1)*(s[i]-s[j]+1);
    }
    printf("%lld\n",f[n]);
}



D[玩具装箱]
题目难度从此开始下降
对于题目里面已经给出的式子,我们直接把它翻译成代码即可

fi=min{fj+(gigjL)2}fi=min{fj+(gi−gj−L)2}
这里gi=si+i,sigi=si+i,si表示前i个玩具长度之和
这里写一下转化式子的步骤,设k<j<i
fi=fj+(gigjL)2<fk+(gigkL)2fi=fj+(gi−gj−L)2<fk+(gi−gk−L)2
fjfk<g2kg2j+2gigj2gigk2gjL+2gk+Lfj−fk<gk2−gj2+2gi∗gj−2gi∗gk−2∗gj∗L+2∗gk+L
fj+g2j+2gjLfkg2k2gkL<2(gjgk)gifj+gj2+2∗gj∗L−fk−gk2−2∗gk∗L<2∗(gj−gk)∗gi
fj+g2j+2gjLfkg2k2gkL2(gjgk)<gifj+gj2+2∗gj∗L−fk−gk2−2∗gk∗L2∗(gj−gk)<gi

后面题目不再重复上述过程

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define N 50010
#define LL long long
using namespace std;
int n,L;
LL s[N],g[N],f[N],q[N];
inline db y(int j){
    return f[j]+g[j]*g[j]+2*g[j]*L;
}
inline db slp(int j,int k){ return (y(j)-y(k))/(2.*(g[j]-g[k])); }
int main(){
    scanf("%d%d",&n,&L); ++L;
    for(int i=1;i<=n;++i){  
        scanf("%lld",s+i);
        s[i]+=s[i-1]; g[i]=s[i]+i;
    }
    int l=0,r=0; f[0]=0;
    for(int i=1,j;i<=n;++i){
        while(l<r && slp(q[l],q[l+1])<=g[i]) ++l; j=q[l];
        f[i]=f[j]+(g[i]-g[j]-L)*(g[i]-g[j]-L);
        while(l<r && slp(q[r-1],q[r])>slp(q[r],i)) --r; q[++r]=i;
    }
    printf("%lld\n",f[n]);
}



E[仓库建设]
经典题目之一
这个题目我们考虑倒着做,因为直接计算距离不是非常方便
先计算出只建立一个仓库的代价之和S
fifi表示最后一个仓库放在i的最大节约代价
那么就可以得到一条非常简洁的转移式子

fi=max{fj+(rjri)sici}fi=max{fj+(rj−ri)∗si−ci}

这里riri是第i个工厂到第n个工厂的距离,sisi是1~i个工厂的产品数量之和

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define N 1000010
#define LL long long
using namespace std;
int n,r[N],p[N],c[N],q[N];
LL s[N],f[N],S=0,g[N];
inline db slp(int j,int k){
    return (f[j]-f[k])/(db)(r[k]-r[j]);
}
int main(){
    scanf("%d",&n); 
    for(int i=1;i<=n;++i) scanf("%d%d%d",r+i,p+i,c+i),s[i]=s[i-1]+p[i];
    for(int i=1;i<n;++i) S+=(r[n]-r[i])*(LL)p[i]; S+=c[n];
    f[n]=0; int h=1,t=0; q[++t]=n;
    for(int i=n-1;i;--i){
        while(h<t && slp(q[h],q[h+1])>=s[i]) ++h;
        f[i]=f[q[h]]+(r[q[h]]-r[i])*s[i]-c[i];
        while(h<t && slp(q[t],q[t-1])<slp(q[t],i)) --t;
        q[++t]=i; *f=max(*f,f[i]);
    }
    printf("%lld\n",S-*f);
}   



F[Cats Transport]
终于来了几道CF的题
和上面一道题一样,我们依然先计算出只用一个feeder时的等待时间之和
让后再计算能优化多少,设fi,jfi,j表示用了i个feeder,最后一个在时刻j出发的答案
那么就得到了和上题几乎一模一样的式子

fi,j=max{fi1,k+(rkrj)sj}fi,j=max{fi−1,k+(rk−rj)∗sj}

注意用滚动数组就可以了,基本没有什么变化

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100010
#define db double
#define LL long long
using namespace std;
int n,m,k,q[N]; LL f[2][N],s[N],S,r[N],p[N],d[N],g[10][1000];;
inline db slp(int j,int k){ return (f[0][j]-f[0][k])/(r[k]-r[j]); }
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=2;i<=n;++i) scanf("%lld",d+i),d[i]+=d[i-1];
    for(int x,i=1;i<=m;++i){
        scanf("%d%lld",&x,r+i); r[i]-=d[x];
    }
    sort(r+1,r+1+m); n=0; r[0]=-1000;
    for(int i=1;i<=m;++i){
        if(r[i]!=r[i-1]){ r[++n]=r[i]; p[n]=1; }
        else ++p[n];
    }
    for(int i=1;i<n;++i){ 
        S+=(r[n]-r[i])*(LL)p[i]; 
        s[i]=s[i-1]+p[i]; 
    }
    for(int T=1;T<k;++T){
        f[0][n]=0; int h=1,t=0; q[++t]=n;
        for(int i=n-1;i;--i){
            while(h<t && slp(q[h],q[h+1])>=s[i]) ++h;
            f[1][i]=f[0][q[h]]+(r[q[h]]-r[i])*s[i];
            while(h<t && slp(q[t],q[t-1])<slp(q[t],i)) --t;
            q[++t]=i;
        }
        swap(f[0],f[1]);
    }
    LL A=0;
    for(int i=1;i<=n;++i) A=max(A,f[0][i]);
    printf("%lld\n",S-A);
}



G[Product Sum]
也是一个比较简单的题
我们设fifi表示移动i能获得最大的贡献
那么考虑把这个i移动到j这个位置,令si=ij=1aisi=∑j=1iai就得到转移式子

fi=max{sisj+(ji)ai}fi=max{si−sj+(j−i)∗ai}

注意到这里并没有i<j的限制,所以我们要选择一项:
1.做两次
2.先求凸包再二分
肯定是第二项比较方便辣

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define LL long long
using namespace std;
int n,m,q[200010];
LL f[200010],v[200010],s[200010],S;
inline db slp(int j,int k){
    return (s[j]-s[k])/(j-k);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%lld",v+i),s[i]=s[i-1]+v[i],S+=v[i]*i;;
    int t=0; q[++t]=0;
    for(int i=1;i<=n;++i){
        while(1<t && slp(q[t-1],q[t])>slp(q[t],i)) --t;
        q[++t]=i;
    }
    for(int i=1;i<=n;++i){
        int l=1,r=t;
        for(int m;l<r;){
            m=l+r>>1;
            if(slp(q[m],q[m+1])<v[i]) l=m+1;
            else r=m;
        }
        f[i]=s[i]-s[q[l]]+(q[l]-i)*v[i];
        *f=max(*f,f[i]);
    }
    printf("%lld\n",*f+S);
}



H[Levels and Regions]
这个题需要推一推式子,然而我期望这方面技巧极差
首先推一推打通第i关所需要的时间Ti,设i所在的Region为[l,r]
那么

Ti=Tii1j=ltjij=ltj+1Ti=Ti∗∑j=li−1tj∑j=litj+1

p=tiij=ltjp=ti∑j=litj那么就得到Ti=(1p)Ti+1Ti=(1−p)Ti+1就是Ti=1+p1Ti=1+p−1
那么整个Region的期望时间E(l,r)就是E(l,r)=ri=lij=ltjtiE(l,r)=∑i=lr∑j=litjti
为了方便dp,我们将这个式子转化一下,首先设Si=ij=1tiSi=∑j=1iti
E(l,r)=i=lrSjSl1ti=i=lrSitiSl1i=lr1tiE(l,r)=∑i=lrSj−Sl−1ti=∑i=lrSiti−Sl−1∗∑i=lr1ti

这里预处理一下 Ai=ij=1Sjtj,Bi=ij=11tjAi=∑j=1iSjtj,Bi=∑j=1i1tj就可以了
最后的dp式子是这样的:
fk,i=min{fk1,j+AiAjSj(BiBj)}fk,i=min{fk−1,j+Ai−Aj−Sj∗(Bi−Bj)}
剩下的就是套路而已

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 200010
#define db double
using namespace std;
int n,k,q[N];
db DP[2][N],AA[N],BB[N],s[N],v[N];
inline db y(int j){
    return DP[0][j]-AA[j]+s[j]*BB[j];
}
inline db slp(int j,int k){
    return (y(j)-y(k))/(s[j]-s[k]);
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i){
        scanf("%lf",v+i);
        s[i]=s[i-1]+v[i];
        AA[i]=AA[i-1]+s[i]/v[i];
        BB[i]=BB[i-1]+1./v[i];
    }
    for(int i=1;i<=n;++i) DP[0][i]=AA[i];
    for(int T=2;T<=k;++T){
        int l=1,r=0; q[++r]=0;
        for(int i=1,j;i<=n;++i){
            while(l<r && slp(q[l],q[l+1])<BB[i]) ++l;
            j=q[l];
            DP[1][i]=DP[0][j]+AA[i]-AA[j]-s[j]*(BB[i]-BB[j]);
            while(l<r && slp(q[r-1],q[r])>=slp(q[r],i)) --r;
            q[++r]=i;
        }
        swap(DP[0],DP[1]);
    }
    printf("%.7lf\n",DP[0][n]);
}



I[序列分割]
回到Bzoj了
发现这个题,无论什么顺序分割序列,最终答案只和分割位置有关
那么计算一下发现就是每个块两两相乘,得到式子
fi,jfi,j表示做到j,用了i块的最大结果
fi,j=max{fi1,k+(sjsk)sk},si=ij=1aifi,j=max{fi−1,k+(sj−sk)∗sk},si=∑j=1iai
滚动数组就没了

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define LL long long
using namespace std;
int n,k,q[100010]; LL f[2][100010],s[100010];
inline LL y(int j){ return f[0][j]-s[j]*s[j]; }
inline db slp(int j,int k){
    if(s[k]==s[j]) return 1e100;
    return (y(j)-y(k))/(s[k]-s[j]);
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i) scanf("%lld",s+i),s[i]+=s[i-1];
    for(int i=1;i<=k;++i){
        int l=1,r=0; q[++r]=0;
        for(int j=1;j<=n;++j){
            while(l<r && slp(q[l],q[l+1])<s[j]) ++l;
            f[1][j]=f[0][q[l]]+(s[j]-s[q[l]])*s[q[l]];
            while(l<r && slp(q[r],q[r-1])>slp(q[r],j)) --r;
            q[++r]=j;
        }
        swap(f[0],f[1]);
    }
    printf("%lld\n",f[0][n]);
}



J[特别行动队]
前面那么多例题,这个题就不说了吧,注意a是负的就行了

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define LL long long
using namespace std;
int n,m,q[1000010],a,b,c;
LL f[1000010],v[1200010],s[1200010],S;
inline LL y(int j){ return f[j]+a*s[j]*s[j]-b*s[j]; }
inline db slp(int j,int k){
    return (y(j)-y(k))/(s[j]-s[k]);
}
int main(){
    scanf("%d%d%d%d",&n,&a,&b,&c);
    for(int i=1;i<=n;++i) scanf("%lld",v+i),s[i]=s[i-1]+v[i];
    int l=1,r=0; q[++r]=0;
    for(int i=1;i<=n;++i){
        while(l<r && slp(q[l],q[l+1])>2.*a*s[i]) ++l;
        int j=q[l];
        f[i]=f[j]+a*(s[i]-s[j])*(s[i]-s[j])+b*(s[i]-s[j])+c;
        while(l<r && slp(q[r-1],q[r])<slp(q[r],i)) --r; q[++r]=i;
    }
    printf("%lld\n",f[n]);
}

转载于:https://www.cnblogs.com/Extended-Ash/p/9477067.html

### 使用 OpenCV 进行霍夫变换检 #### 霍夫变换简介 霍夫变换是一种经典的图像处理技术,主要用于从图像中识别几何形状。通过将图像空间中的点映射到参数空间中的曲线,可以有效地检出直线或其他形状。OpenCV 提供了两种主要的霍夫变换方法:标准霍夫线变换 (`cv2.HoughLines`) 和概率霍夫线变换 (`cv2.HoughLinesP`)[^1]。 #### 标准霍夫线变换 (Standard Hough Line Transform) 标准霍夫线变换适用于检图像中的所有可能直线。它返回一组极坐标表示的直线 `(ρ, θ)`,其中 `ρ` 是原点到直线的距离,`θ` 是法向量的角度。以下是其实现代码: ```python import cv2 import numpy as np # 加载灰度图像并应用边缘检 image = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE) edges = cv2.Canny(image, 50, 150) # 应用标准霍夫线变换 lines = cv2.HoughLines(edges, 1, np.pi / 180, threshold=200) if lines is not None: for line in lines: rho, theta = line[0] a = np.cos(theta) b = np.sin(theta) x0 = a * rho y0 = b * rho x1 = int(x0 + 1000*(-b)) y1 = int(y0 + 1000*(a)) x2 = int(x0 - 1000*(-b)) y2 = int(y0 - 1000*(a)) # 绘制检到的直线 cv2.line(image, (x1, y1), (x2, y2), (255, 0, 0), 2) # 显示结果 cv2.imshow('Hough Lines', image) cv2.waitKey(0) cv2.destroyAllWindows() ``` 此代码实现了基于标准霍夫线变换的直线检,并绘制了检到的直线[^1]。 --- #### 概率霍夫线变换 (Probabilistic Hough Line Transform) 为了提高效率和减少计算复杂度,通常推荐使用概率霍夫线变换。这种方法仅返回满足条件的部分直线段,而不是整条直线。以下是其实现代码: ```python import cv2 import numpy as np # 加载灰度图像并应用边缘检 image = cv2.imread('image.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) edges = cv2.Canny(gray, 50, 150) # 应用概率霍夫线变换 minLineLength = 100 maxLineGap = 10 lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=100, minLineLength=minLineLength, maxLineGap=maxLineGap) if lines is not None: for line in lines: x1, y1, x2, y2 = line[0] cv2.line(image, (x1, y1), (x2, y2), (0, 255, 0), 2) # 显示结果 cv2.imshow('Probabilistic Hough Lines', image) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在此代码中,`cv2.HoughLinesP` 函数被用来检部分直线段,并将其绘制在原始图像上。 --- #### 霍夫圆变换 (Hough Circle Transform) 除了直线检外,霍夫变换还可以用于圆形检。OpenCV 的 `cv2.HoughCircles` 函数结合了 Canny 边缘检和霍夫变换来检图像中的圆。以下是其实现代码: ```python import cv2 import numpy as np # 加载灰度图像 image = cv2.imread('circles.jpg', cv2.IMREAD_GRAYSCALE) # 应用高斯模糊以减少噪声 blurred = cv2.GaussianBlur(image, (9, 9), 2) # 应用霍夫圆变换 circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, dp=1, minDist=50, param1=100, param2=30, minRadius=0, maxRadius=0) if circles is not None: circles = np.uint16(np.around(circles)) for i in circles[0, :]: center = (i[0], i[1]) radius = i[2] # 绘制圆心 cv2.circle(image, center, 1, (0, 100, 100), 3) # 绘制圆周 cv2.circle(image, center, radius, (255, 0, 255), 3) # 显示结果 cv2.imshow('Detected Circles', image) cv2.waitKey(0) cv2.destroyAllWindows() ``` 这段代码展示了如何利用霍夫圆变换检图像中的圆,并标注它们的位置和半径[^2]。 --- #### 检特定斜率范围内的直线 如果需要检具有特定斜率范围的直线,则可以在检完成后筛选符合条件的直线。以下是一个示例代码片段: ```python import math filtered_lines = [] for line in lines: x1, y1, x2, y2 = line[0] slope = abs((y2 - y1) / (x2 - x1)) if (x2 - x1) != 0 else float('inf') # 设置斜率阈值 if 0.5 <= slope <= 2.0: # 斜率介于 0.5 到 2.0 之间 filtered_lines.append(line) # 将过滤后的直线绘制到图像上 for line in filtered_lines: x1, y1, x2, y2 = line[0] cv2.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2) ``` 上述代码演示了如何根据斜率范围筛选直线[^3]。 --- ### 总结 以上介绍了三种常见的霍夫变换应用场景及其对应的实现代码:标准霍夫线变换、概率霍夫线变换以及霍夫圆变换。每种方法都有其适用场景,开发者可以根据具体需求选择合适的算法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值