首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

Python-OpenCV学习(九)直线圆检测

直线和圆检测:Hough变换是直线和形状检测背后的原理基础,它是由Richard Duda和Peter Huart发明,他们是对PaulHough在10世纪60年代早期所做的工作的拓展:直线检测:直线检测通过HoughLines和HoughLinesP函数完成:HoughLines函数用的是标准的Hough变换。HoughLinesP函数使用的是概率Hough变换。HoughLinesP称为概率版本的Hough变换的原因是它只通过分析点的子集并估计这些点属于一条直线的概率,是对标准Hough变换的一个优化,执行速度回更加快: import cv2 import numpy as np img = cv2.imread('lines.jpg') gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) edges = cv2.Canny(gray,50,120) minLineLength = 20 maxLineGap = 5 lines = cv2.HoughLinesP(edges,1,np.pi/180,20,minLineLength,maxLineGap) for x1,y1,x2,y2 in lines[0]: cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2) cv2.imshow("edges", edges) cv2.imshow("lines", img) cv2.waitKey() cv2.destroyAllWindows() 效果设置最小直线长度和最大线段间隙也蛮重要,设置最小会消除小于长度的线段,最大间隙,大于这个值会被视为是两条直线HoughLines输入的位一个边缘检测后的二值化图像:HoughLinesP参数: 需要处理的图像 线段的几何表示rho和theta,一般取1和np.pi/180 阈值。低于这个阈值的线段回本忽略-minLineLength和maxLineGap 圆检测:OpenCV的HoughCircles函数可以用来检测圆,与使用HoughLines函数类似: import cv2 import numpy as np planets = cv2.imread('planet_glow.jpg') gray_img = cv2.cvtColor(planets, cv2.COLOR_BGR2GRAY) img = cv2.medianBlur(gray_img, 5) cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR) circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,120, param1=100,param2=30,minRadius=0,maxRadius=0) circles = np.uint16(np.around(circles)) for i in circles[0,:]: # draw the outer circle cv2.circle(planets,(i[0],i[1]),i[2],(0,255,0),2) # draw the center of the circle cv2.circle(planets,(i[0],i[1]),2,(0,0,255),3) cv2.imwrite("planets_circles.jpg", planets) cv2.imshow("HoughCirlces", planets) cv2.waitKey() cv2.destroyAllWindows()

优秀的个人博客,低调大师

Python-OpenCV学习(八)凸轮廓检测

凸轮廓与Douglas-Peucker算法:大多数处理轮廓的时候,物体的形状(包括凸形状)都是变换多样的。凸形状内部的任意两点的连线都在该形状里面。cv.approxPloyDP是一个计算进似多边形框的函数,该函数有三个参数: 第一个参数为“轮廓” 第二个参数为$\varepsilon $值,它表示圆轮廓与近似多边形的最大差值(这个值越小,近似多边形与源轮廓越接近) 第三个参数为“布尔标记”表示这个多边形是否闭和合$\varepsilon$是为所得到的近似多边形周长与轮廓之间的最大差值,差值越小,多边形轮廓越相似。 如果需要轮廓的周长信息可以通过Opencv的cv2.arcLength函数来完成: epsilon=0.01*cv2.arcLength(cnt,True) approx=cv2.approxPolyDP(cnt,epsilon,True) 通过OpenCV来有效计算一个近似多变形,多边形周长与源轮廓周长之比就为$\varepsilon$为了计算图形状,需要用OpenCV的cv2.convexHull函数来获取处理过的轮廓信息, hull =cv2.convexHull(cnt) 完整代码: import cv2 import numpy as np img = cv2.pyrDown(cv2.imread("hammer.jpg", cv2.IMREAD_UNCHANGED)) ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY) , 127, 255, cv2.THRESH_BINARY) black = cv2.cvtColor(np.zeros((img.shape[1], img.shape[0]), dtype=np.uint8), cv2.COLOR_GRAY2BGR) image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: epsilon = 0.01 * cv2.arcLength(cnt,True) approx = cv2.approxPolyDP(cnt,epsilon,True) hull = cv2.convexHull(cnt) cv2.drawContours(black, [cnt], -1, (0, 255, 0), 2) cv2.drawContours(black, [approx], -1, (255, 255, 0), 2) cv2.drawContours(black, [hull], -1, (0, 0, 255), 2) cv2.imshow("hull", black) cv2.waitKey() cv2.destroyAllWindows()

优秀的个人博客,低调大师

Java-学习笔记-2-工作原理

不足之处,欢迎专家、同行、读者批评指正。 Java的工作原理 Java程序从写代码到实际运行需要经过三个步骤:编写,编译、运行。在不同的阶段,分别生成了不同类型的文件。 在理解工作原理的时候,我们可以看:这个文件由谁产生,给谁使用,是什么类型的。 第一个阶段,编写。 这个阶段由程序员写代码(用什么写无所谓,用记事本写都可以。不过编辑器我推荐Sublime)。写出来以后,保存为“.java”后缀的文件。这个文件是准备给Java编译器的。 第二个阶段,编译。 由编译器,把刚刚写好的“.java”后缀的文件,编译成“.class”后缀的文件。当然不是换个后缀那么简单,点开“.class”看的话会发现是“乱码”,二进制文件——很正常,因为这本来就不是给人看的,是给Java解释器看的。另外,这个转换的过程,会对程序员写的“.java”后缀的文件进行查错,就像老师检查作业一样。如果中间有语法错误,会直接告诉程序员编译不通过,那就得debug了。 第三个阶段,运行。 在此之前,回顾一下“跨平台”的概念。我们知道,Java是跨平台的,然后这个“跨”是通过Java虚拟机实现的。但是这个Java虚拟机在不同的操作系统中是不一样的,那到底是什么东西真正在“跨”呢?就是上一步生成的“.class”文件。这个是给虚拟机用的。不同操作系统的虚拟机,运行相同的“.class”文件,效果是一样的,所以说它跨平台了。这就是所谓的二进制代码级别的跨平台移植。 回来说说运行。运行是由Java解释器,把“.class”文件翻译成机器代码,一边执行一边显示结果的过程。这个Java解释器是上文我提到的Java虚拟机中的一部分。 关于“边解释边运行”,可以说一下。这个其实不是绝对的。因为Java解释器其实 不止一种,我们是可以选择的。另外,字节码其实也不是必须的,只不过字节码对于虚拟机来说读起来更快。字节码甚至可以由其他的语言生成,这就涉及到不同语言的混编了。

优秀的个人博客,低调大师

算法学习之路|数据结构--堆

堆(英语:heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:堆中某个节点的值总是不大于或不小于其父节点的值;堆总是一棵完全二叉树。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。(ki <= k2i,ki = k2i,ki >= k2i+1), (i = 1,2,3,4...n/2)若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。ps:以上定义来自百度百科1.保持堆的性质该操作主要用于维持堆的基本性质。假定以节点t的左孩子节点和节点t的右孩子节点为根的子树都已经是堆,然后调整以t为根的子树,使之成为堆。 void Heapify(int A[],int i,int n)//A[]为堆的数组,i表示i节点,n为A中元素个数 { int l=2*i; int r=2*i+1; int largest=i; if(l<=n) largest=A[l]>A[i]?l:i; if(r<=n) largest=A[r]>A[largest]?r:largest; //从i,2*i,2*i+1中找出最大的一个 if(largest!=i) //i不是最大的 { swap(A[i],A[largest]);//交换 Heapify(A,largest,n); //交换后,子树有可能违反最大堆性质 } } 2.建堆 操作主要是将数组A转化成一个大顶堆。思想是,先找到堆的最后一个非叶子节点(即为第n/2个节点),然后从该节点开始,从后往前逐个调整每个子树,使之称为堆,最终整个数组便是一个堆。 void BuildHeap(int A[],int n) { int i; for(i = n/2; i>=1; i--) Heapify(A, i); } 3.堆排序先用BuildHeapo将数组A[1..n]构造成一个最大堆。再将最大的元素A[1]和A[n]交换,再数组A[1..n-1]构造成一个最大堆,直到排序完成 void HeapSort(int A[],int n) { BuildHeap(A,n); for(i=n;i>1; i--) { swap(A[1],A[i]); Heapify(A,1,n-1); //交换后新的根元素可能委培了最大堆的性质 } } 4.优先队列 优先队列是一种用来维护由一组元素构成的集合S的数据机构。相信大家对它都有所了解。虽然说c++里面有了priority_queue,但我们还是要了解它的一些基本构成及实现的代码。GETMAX:该操作主要是获取堆中最大的元素,同时保持堆的基本性质。堆的最大元素即为第一个元素,将其保存下来,同时将最后一个元素放到A[1]位置,之后从上往下调整A,使之成为一个堆 void GetMaximum(int A[],int n) { int max = A[1]; A[1] = A[n]; Heapify(A, 1, n-1); return max; } INSERT: 向堆中添加一个元素t,同时保持堆的性质。算法思想是,将t放到A的最后,然后从该元素开始,自下向上调整,直至A成为一个大顶堆。 void Insert(int A[], int i,int n) { //i为插入的值 n++; int p = n; while(p >1 && A[floor(p/2)] < i) //floor()向下取整 { A[p] = A[floor(p/2)]; p =floor(p/2); } A[p]=i; }

优秀的个人博客,低调大师

google protobuf学习笔记二:使用和原理

一.什么是protobuf protobuf全称Google Protocol Buffers,是google开发的的一套用于数据存储,网络通信时用于协议编解码的工具库。它和XML或者JSON差不多,也就是把某种数据结构的信息,以某种格式(XML,JSON)保存起来,protobuf与XML和JSON不同在于,protobuf是基于二进制的。主要用于数据存储、传输协议格式等场合。那既然有了XML等工具,为什么还要开发protobuf呢?主要是因为性能,包括时间开销和空间开销: 1.时间开销:XML格式化(序列化)和XML解析(反序列化)的时间开销是很大的,在很多时间性能上要求很高的场合,你能做的就是看着XML干瞪眼了。 2.空间开销:熟悉XML语法的同学应该知道,XML格式为了有较好的可读性,引入了一些冗余的文本信息。所以空间开销也不是太好(应该说是很差,通常需要实际内容好几倍的空间)。 据实验(当然不是我实验),一条消息数据,用protobuf序列化后的大小是json格式的十分之一,xml格式的二十分之一。 这一篇主要讲protobuf用作数据存储方面,下一篇讲用作rpc通讯协议方面。 二.使用protobuf 注:我只会讲语言特性,至于环境配置之类的,请大家http://www.bieryun.com/870.html protobuf的使用很简单,开发人员按照一定的语法定义结构化的消息格式,然后用自带的编译工具,工具将自动生成相关的类,官方支持java、c++、python语言环境(当然可以在网上找到很多支持其他语言的封装,当然你也可以自己写一个,只要符合google定义的格式)。通过将这些类包含在项目中,可以很轻松的调用相关方法来完成业务消息的序列化与反序列化工作。 1.定义报文格式。protobuf文件的后缀是proto,是一种类似c++或者java的语法。使用protoc.exe(windows平台下,你可以下载源码编译,也可以网上直接下载exe,这个大家自行Google)把proto文件编译成c++,java或者Python就可以使用了。 [cpp] view plain copy packagetutorial; messagePerson{ requiredstringname=1; requiredint32age=2; optionalstringemail=3; } 在这里定义了一个Person,我们只是简单的定义了name,age和email。这里注意,在上例中,package 名字叫做 tutorial,相当于c++的namespace,定义了一个消息 Person,该消息有3个成员,类型为 string 的 name,类型为 int32 的成员 age和类型为string的email。optional 代表这是一个可选的成员,即消息中可以不包含该成员,required代表是必须的。 写好proto之后把proto放在protoc.exe相同目录,然后在此目录使用指令:protoc --cpp_out=d:\proto person.proto(我们使用的是c++)。当用protocolbuffer编译器来运行.proto文件时,编译器将生成所选择语言的代码,这些代码可以操作在.proto文件中定义的消息类型,包括获取、设置字段值,将消息序列化到一个输出流中,以及从一个输入流中解析消息。 就可以生成person.pb.h,person.pb.cc.在生成的头文件中,定义了一个 C++ 类 Person,继承自google::protobuf::Message,后面我们进行对Person数据的文件读写, 将使用这个类来对消息进行操作。诸如对消息的成员进行赋值,将消息序列化等等都有相应的方法。 首先,把数据写入disk: [cpp] view plain copy #include<iostream> #include<fstream> #include"person.pb.h" #pragmacomment(lib,"libprotobuf.lib") #pragmacomment(lib,"libprotoc.lib") usingnamespacestd; usingnamespacetutorial; intmain() { Personperson; person.set_name("flamingo"); person.set_age(18); person.set_email("majianfei1023@gmail.com"); //Write fstreamoutput("./log",ios::out|ios::trunc|ios::binary); if(!person.SerializeToOstream(&output)){ cerr<<"Failedtowritemsg."<<endl; return-1; } system("pause"); return0; } namespace tutorial就是我们之前定义的package,我们先定义一个Person,然后给Person赋值,其中set_name,set_age,set_email是根据proto自动生成的,我们使用SerializeToOstream 将对象序列化成二进制(导致了可读性差的问题,这算是protobuf的一个缺点吧)后写入一个 fstream 流。 然后在从disk读出Person的数据: [cpp] view plain copy #include<iostream> #include<fstream> #include"person.pb.h" #pragmacomment(lib,"libprotobuf.lib") #pragmacomment(lib,"libprotoc.lib") usingnamespacestd; usingnamespacetutorial; voidPrintInfo(constPerson&person){ cout<<person.name()<<endl; cout<<person.age()<<endl; cout<<person.email()<<endl; } intmain() { Personperson; fstreaminput("./log",ios::in|ios::binary); if(!person.ParseFromIstream(&input)){ cerr<<"Failedtoparseaddressbook."<<endl; return-1; } PrintInfo(person); system("pause"); return0; } 主要是利用 ParseFromIstream 从一个 fstream 流中读取序列化的信息并反序列化。 原文地址http://www.bieryun.com/875.html

优秀的个人博客,低调大师

Gradle学习之构建java与web项目

一.使用Gradle的java插件构建Java项目 1)Gradle插件包含了若干个接口定义和已有的任务项,语法结构:apply plugin:'插件名' ,此处我们定义插件 apply plugin : 'java' 2)Gradle希望我们的java项目需要遵循以下规范: src/main/java :放置java源文件 src/test/java :放置测试文件,比如单元测试等 src/main/resources: 此目录下的文件会被作为资源文件打入jar包 src/test/resources: 放置提供给测试用的配置文件 3) java插件包含了若干个构建项目的任务,最常用的就是build任务,当我们运行build任务时,Gradle会编译,运行我们的测试脚本(类)并生成jar文件在build/lib下 4) 其他常用的任务: clean:删除已经构建的目录及其文件 assemble:编译并生成Jar或者war文件,注意不会运行测试文件 check:编译并测试代码 二.外部依赖 1)和maven类似,如果要在项目中添加所依赖的外部jar文件,我们必须要告诉Gradle在哪里找到它们 语法: 1 repositories { 2 jcenter() 3 mavenLocal() //maven本地仓库 4 mavenCentral() //maven中心仓库 5 /* 6 指定maven远程仓库地址 7 */ 8 maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } 9 maven { url "http://repo.spring.io/snapshot" } 10 maven { url "http://repo.spring.io/milestone" } 11 } 2)当指定好仓库地址时,我们可以添加依赖 语法: dependencies{ compile group:'类似于maven中的groupid',name:'类似于maven中的affactid',version:'版本号' compile 'group:name:version' } 三.java多项目构建 1)gradle也可以支持多项目构建,比如说如下项目: multiproject/ api/ services/webservice/ shared/ services/shared/2)此时我们要在settings.gradle里配置 依赖的模块: include "shared", "api", "services:webservice", "services:shared" 3)比如说 shared模块要依赖api模块 我们可以在shared模块中的build.gradle文件中这样写: dependencies { compile project(':shared') } 4)常见属性 sourceCompatibility: 使用哪种JDK版本编译 targetCompatibility : 生成class的Java版本 四。构建web项目 1)需要添加web插件:apply plugin:'war'2) war任务 主要用于将web应用程序打包成war3) 与maven规范一致:web的相关资源位于src/main/webapp下 使用示例: war { from 'src/rootContent' // adds a file-set to the root of the archive webInf { from 'src/additionalWebInf' } // adds a file-set to the WEB-INF dir. classpath fileTree('additionalLibs') // adds a file-set to the WEB-INF/lib dir. classpath configurations.moreLibs // adds a configuration to the WEB-INF/lib dir. webXml = file('src/someWeb.xml') // copies a file to WEB-INF/web.xml } 另外我们可以设置webAppDirName来指定我们web上下文路径

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册