@@ -228,7 +228,12 @@ | |||||
<artifactId>javase</artifactId> | <artifactId>javase</artifactId> | ||||
<version>3.3.0</version> | <version>3.3.0</version> | ||||
</dependency> | </dependency> | ||||
<!-- hutool工具类 --> | |||||
<dependency> | |||||
<groupId>cn.hutool</groupId> | |||||
<artifactId>hutool-all</artifactId> | |||||
<version>4.6.1</version> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
<build> | <build> | ||||
@@ -3,6 +3,8 @@ package com.acts.opencv.base; | |||||
import java.awt.image.BufferedImage; | import java.awt.image.BufferedImage; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Collections; | |||||
import java.util.Comparator; | |||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
@@ -17,6 +19,7 @@ import org.opencv.core.Mat; | |||||
import org.opencv.core.MatOfFloat; | import org.opencv.core.MatOfFloat; | ||||
import org.opencv.core.MatOfInt; | import org.opencv.core.MatOfInt; | ||||
import org.opencv.core.MatOfPoint; | import org.opencv.core.MatOfPoint; | ||||
import org.opencv.core.MatOfPoint2f; | |||||
import org.opencv.core.Point; | import org.opencv.core.Point; | ||||
import org.opencv.core.Rect; | import org.opencv.core.Rect; | ||||
import org.opencv.core.Scalar; | import org.opencv.core.Scalar; | ||||
@@ -42,6 +45,8 @@ import com.google.zxing.Result; | |||||
import com.google.zxing.client.j2se.BufferedImageLuminanceSource; | import com.google.zxing.client.j2se.BufferedImageLuminanceSource; | ||||
import com.google.zxing.common.HybridBinarizer; | import com.google.zxing.common.HybridBinarizer; | ||||
import cn.hutool.core.util.NumberUtil; | |||||
@Controller | @Controller | ||||
@RequestMapping(value = "base") | @RequestMapping(value = "base") | ||||
@@ -1083,4 +1088,221 @@ public class BaseMethodController extends BaseController { | |||||
// | // | ||||
// } | // } | ||||
public static void main(String[] args) { | |||||
System.loadLibrary(Core.NATIVE_LIBRARY_NAME); | |||||
} | |||||
@RequestMapping(value = "picTransform") | |||||
public void picTransform(HttpServletResponse response, String imagefile) { | |||||
System.loadLibrary(Core.NATIVE_LIBRARY_NAME); | |||||
logger.info("\n 图像转换开始"); | |||||
//我们假设我们识别的图片如样例一样有明显的边界,那我们可以用边缘检测算法将真正有效区域抽离出来, | |||||
//以此来提高识别准确度和识别精度 | |||||
//先进行边缘检测 | |||||
// String sourcePath = "d:\\test\\abc\\a.png"; | |||||
String sourcePath = Constants.PATH + imagefile; | |||||
Mat source = Highgui.imread(sourcePath); | |||||
// Mat destination = new Mat(source.rows(), source.cols(), source.type()); | |||||
//复制一个source作为四点转换的原图,因为source在轮廓识别时会被覆盖,建议图像处理时都将原图复制一份, | |||||
//因为opencv的很多算法都会更改传入的soure图片,如果不注意可能就会导致各种异常。 | |||||
Mat orign = source.clone(); | |||||
//为了加速图像处理,以及使我们的边缘检测步骤更加准确,我们将扫描图像的大小调整为具有500像素的高度。 | |||||
Mat dst = source.clone(); | |||||
//缩放比例 | |||||
double ratio = NumberUtil.div(500, orign.height()); | |||||
System.out.println("----------"+ratio); | |||||
double width = ratio*orign.width(); | |||||
Imgproc.resize(source, dst, new Size(width,500)); | |||||
// 灰度化,加载为灰度图显示 | |||||
Mat gray = dst.clone(); | |||||
Imgproc.cvtColor(dst,gray,Imgproc.COLOR_BGR2GRAY); | |||||
Highgui.imwrite("d:\\test\\abc\\o1.png", gray); | |||||
//高斯滤波,去除杂点等干扰 | |||||
Imgproc.GaussianBlur(gray,gray, new Size(5, 5), 0); | |||||
//canny边缘检测算法,经过canny算法或的图像会变成二值化效果 | |||||
Mat edges = gray.clone(); | |||||
Imgproc.Canny(gray,edges,75, 200); | |||||
Highgui.imwrite("d:\\test\\abc\\o2.png", edges); | |||||
String destPath = "d:\\test\\abc\\dst.png"; | |||||
Mat hierarchy = new Mat(gray.rows(), gray.cols(), CvType.CV_8UC1, new Scalar(0)); | |||||
Vector<MatOfPoint> contours = new Vector<MatOfPoint>(); | |||||
//轮廓识别,查找外轮廓 | |||||
Imgproc.findContours(edges, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE, new Point()); | |||||
List<Point> listPoint = new ArrayList<>(); | |||||
for(int i =0; i<contours.size();i++) { | |||||
MatOfPoint2f newPoint = new MatOfPoint2f(contours.get(i).toArray()); | |||||
// 周长,第1个参数是轮廓,第二个参数代表是否是闭环的图形 | |||||
double peri = 0.01 * Imgproc.arcLength(newPoint, true); | |||||
MatOfPoint2f approx = new MatOfPoint2f(); | |||||
// approx.convertTo(approx, CvType.CV_32F); | |||||
//近似轮廓逼近,然后通过获取多边形的所有定点,如果是四个定点,就代表是矩形 | |||||
Imgproc.approxPolyDP(newPoint,approx, peri, true); | |||||
//只考虑矩形,如果近似轮廓有4个点,我们就认为已经找到了该矩形。 | |||||
if (approx.rows() == 4) { | |||||
//通过reshape函数将4个点取出来(4行2列的矩阵) | |||||
Mat points = approx.reshape(2, 4); | |||||
System.out.println(points.dump()); | |||||
double[] point1 = points.get(0, 0); | |||||
double[] point2 = points.get(1, 0); | |||||
double[] point3 = points.get(2, 0); | |||||
double[] point4 = points.get(3, 0); | |||||
//之前因为我们已经将图片进行了缩放,所以此处要将图片尺寸还原 | |||||
listPoint.add(new Point(point1[0]/ratio,point1[1]/ratio)); | |||||
listPoint.add(new Point(point2[0]/ratio,point2[1]/ratio)); | |||||
listPoint.add(new Point(point3[0]/ratio,point3[1]/ratio)); | |||||
listPoint.add(new Point(point4[0]/ratio,point4[1]/ratio)); | |||||
for (Point d : listPoint) { | |||||
System.out.println(d); | |||||
} | |||||
System.out.println("######################"); | |||||
break; | |||||
} | |||||
} | |||||
//绘制轮廓,注意是在缩放过的图片上绘制的,别在原图上画,肯定画的不对。 | |||||
Imgproc.drawContours(dst, contours, -1, new Scalar(0, 255, 0), 2); | |||||
Highgui.imwrite("d:\\test\\abc\\o3.png", dst); | |||||
Mat resullt = fourPointTransform(orign, listPoint); | |||||
Highgui.imwrite(destPath, resullt); | |||||
// 方式2,回写页面图片流 | |||||
try { | |||||
byte[] imgebyte = OpenCVUtil.covertMat2Byte1(resullt); | |||||
renderImage(response, imgebyte); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
/** | |||||
* py中imutils中经典的4点转换方法的java实现 | |||||
* @author song.wang | |||||
* @date 2019年8月20日 | |||||
* @param source | |||||
* @param listPoint | |||||
* @return Mat | |||||
* | |||||
* 更新日志 | |||||
* 2019年8月20日 song.wang 首次创建 | |||||
*/ | |||||
private static Mat fourPointTransform(Mat source,List<Point> listPoint) { | |||||
//获得点的顺序 | |||||
List<Point> newOrderList = orderPoints(listPoint); | |||||
for (Point point : newOrderList) { | |||||
System.out.println(point); | |||||
} | |||||
//计算新图像的宽度,它将是右下角和左下角x坐标之间或右上角和左上角x坐标之间的最大距离 | |||||
//此处的顺序别搞错0,1,2,3依次是左上[0],右上[1],右下[2],左下[3] | |||||
Point leftTop = newOrderList.get(0); | |||||
Point rightTop = newOrderList.get(1); | |||||
Point rightBottom = newOrderList.get(2); | |||||
Point leftBottom = newOrderList.get(3); | |||||
double widthA = Math.sqrt(Math.pow(rightBottom.x-leftBottom.x, 2) | |||||
+Math.pow(rightBottom.y-leftBottom.y, 2)); | |||||
double widthB = Math.sqrt(Math.pow(rightTop.x-leftTop.x, 2) | |||||
+Math.pow(rightTop.y-leftTop.y, 2)); | |||||
int maxWidth = Math.max((int)widthA, (int)widthB); | |||||
//计算新图像的高度,这将是右上角和右下角y坐标或左上角和左下角y坐标之间的最大距离, | |||||
//这里用到的初中数学知识点和点的距离计算(x1,y1),(x2,y2)距离=√((x2-x1)^2+(y2-y1)^2) | |||||
double heightA = Math.sqrt(Math.pow(rightTop.x-rightBottom.x, 2) | |||||
+Math.pow(rightTop.y-rightBottom.y, 2)); | |||||
double heightB = Math.sqrt(Math.pow(leftTop.x-leftBottom.x, 2) | |||||
+Math.pow(leftTop.y-leftBottom.y, 2)); | |||||
int maxHeight = Math.max((int)heightA, (int)heightB); | |||||
System.out.println("宽度:"+maxWidth); | |||||
System.out.println("高度:"+maxHeight); | |||||
//现在我们指定目标图像的尺寸,构造目标点集以获得图像的“鸟瞰图”(即自上而下的视图), | |||||
//再次指定左上角,右上角的点,右下角和左下角的顺序 | |||||
Point dstPoint1 = new Point(0,0); | |||||
Point dstPoint2 = new Point(maxWidth-1,0); | |||||
Point dstPoint3 = new Point(maxWidth-1,maxHeight-1); | |||||
Point dstPoint4 = new Point(0,maxHeight-1); | |||||
//计算透视变换矩阵rectMat原四顶点位置,dstMat目标顶点位置 | |||||
MatOfPoint2f rectMat = new MatOfPoint2f(leftTop,rightTop,rightBottom,leftBottom); | |||||
MatOfPoint2f dstMat = new MatOfPoint2f(dstPoint1, dstPoint2, dstPoint3, dstPoint4); | |||||
//opencv透视转换方法 | |||||
Mat transmtx = Imgproc.getPerspectiveTransform(rectMat, dstMat); | |||||
//注意定义的新图像宽高设置 | |||||
Mat resultMat = Mat.zeros((int)maxHeight-1, (int)maxWidth-1, CvType.CV_8UC3); | |||||
Imgproc.warpPerspective(source, resultMat, transmtx, resultMat.size()); | |||||
Highgui.imwrite("D:\\test\\abc\\t2.png", resultMat); | |||||
//返回矫正后的图像 | |||||
return resultMat; | |||||
} | |||||
/** | |||||
* 4点排序,四个点按照左上、右上、右下、左下组织返回 | |||||
* @author song.wang | |||||
* @date 2019年8月16日 | |||||
* @param listPoint | |||||
* @return List<Point> | |||||
* | |||||
* 更新日志 | |||||
* 2019年8月16日 song.wang 首次创建 | |||||
*/ | |||||
private static List<Point> orderPoints(List<Point> listPoint) { | |||||
//python中有很多关于数组的函数处理如排序、比较、加减乘除等,在这里我们使用List进行操作 | |||||
//如numpy.argsort;numpy.argmin;numpy.argmax;sum(axis = 1);diff(pts, axis = 1)等等,有兴趣的可以查阅相关资料 | |||||
//四个点按照左上、右上、右下、左下组织返回 | |||||
//直接在这里添加我们的排序规则,按照x坐标轴升序排列,小的放前面 | |||||
Collections.sort(listPoint, new Comparator<Point>() { | |||||
public int compare(Point arg0, Point arg1) { | |||||
if(arg0.x < arg1.x){ | |||||
return -1; | |||||
}else if (arg0.x> arg1.x){ | |||||
return 1; | |||||
}else{ | |||||
return 0; | |||||
} | |||||
} | |||||
}); | |||||
//排序之后前2个点就是左侧的点,后2个点为右侧的点 | |||||
//对比Y轴,y值小的是左上的点,y大的是左下的点 | |||||
Point top_left = new Point(); | |||||
Point bottom_left = new Point(); | |||||
Point top_right = new Point(); | |||||
Point bottom_right = new Point(); | |||||
Point leftPoint1 = listPoint.get(0); | |||||
Point leftPoint2 = listPoint.get(1); | |||||
Point rightPoint1 = listPoint.get(2); | |||||
Point rightPoint2 = listPoint.get(3); | |||||
if(leftPoint1.y > leftPoint2.y){ | |||||
top_left = leftPoint2; | |||||
bottom_left = leftPoint1; | |||||
}else{ | |||||
top_left = leftPoint1; | |||||
bottom_left = leftPoint2; | |||||
} | |||||
//定位右侧的2个点右上和右下使用方法是毕达哥拉斯定理,就是勾股定理距离长的认为是右下角 | |||||
//计算左上方点和右侧两个点的欧氏距离 | |||||
//(y2-y1)^2+(x2-x1)^2 开根号 | |||||
double rightLength1 = Math.sqrt(Math.pow((rightPoint1.y - top_left.y), 2) | |||||
+ Math.pow((rightPoint1.x - top_left.x), 2)); | |||||
double rightLength2 = Math.sqrt(Math.pow((rightPoint2.y - top_left.y), 2) | |||||
+ Math.pow((rightPoint2.x - top_left.x), 2)); | |||||
if(rightLength1>rightLength2){ | |||||
//长度长的那个是右下角,短的为右上角;这个算法有一种情况会有可能出问题,比如倒梯形,但是在正常的俯角拍摄时不会出现这种情况 | |||||
//还有一种方案是按照左侧的那种对比方案,根据y轴的高度判断。 | |||||
top_right = rightPoint2; | |||||
bottom_right = rightPoint1; | |||||
}else{ | |||||
top_right = rightPoint1; | |||||
bottom_right = rightPoint2; | |||||
} | |||||
//按照左上,右上,右下,左下的顺时针顺序排列,这点很重要,透视变换时根据这个顺序进行对应 | |||||
List<Point> newListPoint = new ArrayList<>(); | |||||
newListPoint.add(top_left); | |||||
newListPoint.add(top_right); | |||||
newListPoint.add(bottom_right); | |||||
newListPoint.add(bottom_left); | |||||
return newListPoint; | |||||
} | |||||
} | } |
@@ -34,61 +34,61 @@ | |||||
</bean> | </bean> | ||||
<!--dataSource--> | <!--dataSource--> | ||||
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> | |||||
<!-- 数据库基本信息配置 --> | |||||
<!-- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> | |||||
数据库基本信息配置 | |||||
<property name="driverClassName" value="${driverClassName}" /> | <property name="driverClassName" value="${driverClassName}" /> | ||||
<property name="Url" value="${url}" /> | <property name="Url" value="${url}" /> | ||||
<property name="username" value="${username}" /> | <property name="username" value="${username}" /> | ||||
<property name="password" value="${password}" /> | <property name="password" value="${password}" /> | ||||
<!-- 初始化连接数量 --> | |||||
初始化连接数量 | |||||
<property name="initialSize" value="${initialSize}" /> | <property name="initialSize" value="${initialSize}" /> | ||||
<!-- 最大并发连接数 --> | |||||
最大并发连接数 | |||||
<property name="maxActive" value="${maxActive}" /> | <property name="maxActive" value="${maxActive}" /> | ||||
<!-- 最小空闲连接数 --> | |||||
最小空闲连接数 | |||||
<property name="minIdle" value="${minIdle}" /> | <property name="minIdle" value="${minIdle}" /> | ||||
<!-- 配置获取连接等待超时的时间 --> | |||||
配置获取连接等待超时的时间 | |||||
<property name="maxWait" value="${maxWait}" /> | <property name="maxWait" value="${maxWait}" /> | ||||
<!-- 超过时间限制是否回收 --> | |||||
超过时间限制是否回收 | |||||
<property name="removeAbandoned" value="${removeAbandoned}" /> | <property name="removeAbandoned" value="${removeAbandoned}" /> | ||||
<!-- 超过时间限制多长; --> | |||||
超过时间限制多长; | |||||
<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" /> | <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" /> | ||||
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> | |||||
配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 | |||||
<property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" /> | <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" /> | ||||
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> | |||||
配置一个连接在池中最小生存的时间,单位是毫秒 | |||||
<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" /> | <property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" /> | ||||
<!-- 用来检测连接是否有效的sql,要求是一个查询语句 ||抛弃此种方式的连接检查--> | |||||
<!-- <property name="validationQuery" value="${validationQuery}" /> --> | |||||
<!-- 申请连接的时候检测 --> | |||||
用来检测连接是否有效的sql,要求是一个查询语句 ||抛弃此种方式的连接检查 | |||||
<property name="validationQuery" value="${validationQuery}" /> | |||||
申请连接的时候检测 | |||||
<property name="testWhileIdle" value="${testWhileIdle}" /> | <property name="testWhileIdle" value="${testWhileIdle}" /> | ||||
<!-- 申请连接时执行validationQuery检测连接是否有效,配置为true会降低性能 --> | |||||
申请连接时执行validationQuery检测连接是否有效,配置为true会降低性能 | |||||
<property name="testOnBorrow" value="${testOnBorrow}" /> | <property name="testOnBorrow" value="${testOnBorrow}" /> | ||||
<!-- 归还连接时执行validationQuery检测连接是否有效,配置为true会降低性能 --> | |||||
归还连接时执行validationQuery检测连接是否有效,配置为true会降低性能 | |||||
<property name="testOnReturn" value="${testOnReturn}" /> | <property name="testOnReturn" value="${testOnReturn}" /> | ||||
<!-- 打开PSCache,并且指定每个连接上PSCache的大小 --> | |||||
打开PSCache,并且指定每个连接上PSCache的大小 | |||||
<property name="poolPreparedStatements" value="${poolPreparedStatements}" /> | <property name="poolPreparedStatements" value="${poolPreparedStatements}" /> | ||||
<property name="maxPoolPreparedStatementPerConnectionSize" value="${maxPoolPreparedStatementPerConnectionSize}" /> | <property name="maxPoolPreparedStatementPerConnectionSize" value="${maxPoolPreparedStatementPerConnectionSize}" /> | ||||
<!--属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: | |||||
属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: | |||||
监控统计用的filter:stat | 监控统计用的filter:stat | ||||
日志用的filter:log4j | 日志用的filter:log4j | ||||
防御SQL注入的filter:wall --> | |||||
防御SQL注入的filter:wall | |||||
<property name="filters" value="${filters}" /> | <property name="filters" value="${filters}" /> | ||||
</bean> | |||||
</bean> --> | |||||
<!-- Hibernate对Jpa的实现 --> | <!-- Hibernate对Jpa的实现 --> | ||||
<bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> | <bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> | ||||
<!-- 配置 JPA 的 EntityManagerFactory --> | <!-- 配置 JPA 的 EntityManagerFactory --> | ||||
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> | |||||
<!-- 指定数据源 --> | |||||
<!-- <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> | |||||
指定数据源 | |||||
<property name="dataSource" ref="dataSource"/> | <property name="dataSource" ref="dataSource"/> | ||||
<!-- 指定Jpa持久化实现厂商类,这里以Hibernate为例 --> | |||||
指定Jpa持久化实现厂商类,这里以Hibernate为例 | |||||
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/> | <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/> | ||||
<!-- 指定Entity实体类包路径 --> | |||||
指定Entity实体类包路径 | |||||
<property name="packagesToScan" value="com.acts.opencv"></property> | <property name="packagesToScan" value="com.acts.opencv"></property> | ||||
<!-- 指定JPA属性;如Hibernate中指定是否显示SQL的是否显示、方言等 --> | |||||
指定JPA属性;如Hibernate中指定是否显示SQL的是否显示、方言等 | |||||
<property name="jpaProperties"> | <property name="jpaProperties"> | ||||
<props> | <props> | ||||
<!-- <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop> --> | |||||
<!-- <prop key="hibernate.hbm2ddl.auto">update</prop> --> | |||||
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop> | |||||
<prop key="hibernate.hbm2ddl.auto">update</prop> | |||||
<prop key="hibernate.show_sql">true</prop> | <prop key="hibernate.show_sql">true</prop> | ||||
<prop key="hibernate.format_sql">false</prop> | <prop key="hibernate.format_sql">false</prop> | ||||
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> | <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop> | ||||
@@ -99,20 +99,20 @@ | |||||
</props> | </props> | ||||
</property> | </property> | ||||
<property name="sharedCacheMode" value="ENABLE_SELECTIVE"></property> | <property name="sharedCacheMode" value="ENABLE_SELECTIVE"></property> | ||||
</bean> | |||||
</bean> --> | |||||
<!-- 定义事务 --> | <!-- 定义事务 --> | ||||
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> | |||||
<!-- <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> | |||||
<property name="entityManagerFactory" ref="entityManagerFactory"/> | <property name="entityManagerFactory" ref="entityManagerFactory"/> | ||||
</bean> | |||||
</bean> --> | |||||
<!-- 配置 Annotation 驱动,扫描@Transactional注解的类定义事务 --> | <!-- 配置 Annotation 驱动,扫描@Transactional注解的类定义事务 --> | ||||
<tx:annotation-driven transaction-manager="transactionManager"/> | |||||
<!-- <tx:annotation-driven transaction-manager="transactionManager"/> | |||||
<!-- 配置 SpringData --> | |||||
配置 SpringData | |||||
<jpa:repositories base-package="com.acts.opencv" entity-manager-factory-ref="entityManagerFactory"/> | <jpa:repositories base-package="com.acts.opencv" entity-manager-factory-ref="entityManagerFactory"/> | ||||
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> | <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> | ||||
<property name="dataSource" ref="dataSource"/> | <property name="dataSource" ref="dataSource"/> | ||||
</bean> | |||||
</bean> --> | |||||
<!-- redis 配置 | <!-- redis 配置 | ||||
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" /> | <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" /> | ||||
@@ -141,6 +141,7 @@ desired effect | |||||
<li><a href="#view/base/contours.jsp"><i class="fa fa-circle-o"></i>轮廓</a></li> | <li><a href="#view/base/contours.jsp"><i class="fa fa-circle-o"></i>轮廓</a></li> | ||||
<li><a href="#view/base/findtemplate.jsp"><i class="fa fa-circle-o"></i>模板查找</a></li> | <li><a href="#view/base/findtemplate.jsp"><i class="fa fa-circle-o"></i>模板查找</a></li> | ||||
<li><a href="#view/base/grayHistogram.jsp"><i class="fa fa-circle-o"></i>灰度直方图</a></li> | <li><a href="#view/base/grayHistogram.jsp"><i class="fa fa-circle-o"></i>灰度直方图</a></li> | ||||
<li><a href="#view/base/fourPointTransform.jsp"><i class="fa fa-circle-o"></i>4点转换矫正</a></li> | |||||
</ul> | </ul> | ||||
</li> | </li> | ||||
@@ -0,0 +1,112 @@ | |||||
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> | |||||
<%@include file="/module/include/common.jsp"%> | |||||
<!DOCTYPE html> | |||||
<html> | |||||
<head> | |||||
<sys:header title="首页" extLibs=""></sys:header> | |||||
<link rel="stylesheet" href="${ctxStatic}/plugins/iCheck/all.css?t=${version}"> | |||||
<link rel="stylesheet" href="${ctxStatic}/plugins/bootstrap-slider/slider.css"> | |||||
<link rel="stylesheet" href="${ctxStatic}/plugins/iCheck/minimal/blue.css?t=${version}"> | |||||
<script type="text/javascript"> | |||||
$(function(){ | |||||
var baseImageFile = "/statics/sourceimage/pic_transform.png" | |||||
//var baseImageFile = "/statics/sourceimage/ada.png" | |||||
var newImagePath = "/statics/distimage/pic_transform.png" | |||||
$("#oldimg").attr("src",baseUrl+baseImageFile); | |||||
//$("#newimg").attr("src",baseUrl+baseImageFile); | |||||
//二值化 | |||||
$("#handle").click(function(){ | |||||
var imagefile = baseImageFile; | |||||
//方式2,实时传输图片流的方式 | |||||
var srcurl = ctxPath+"/base/picTransform?_" + $.now()+"&imagefile="+baseImageFile; | |||||
$("#newimg").attr("src",srcurl); | |||||
}); | |||||
//重置 | |||||
$("#reset").click(function(){ | |||||
var baseImageFile = "/statics/sourceimage/pic_transform.png"; | |||||
$("#oldimg").attr("src",baseUrl+baseImageFile); | |||||
$("#newimg").attr("src",''); | |||||
layer.msg('重置成功!', {icon: 1}); | |||||
}); | |||||
}); | |||||
</script> | |||||
</head> | |||||
<body> | |||||
<div class="box-body"> | |||||
<div class="box-group" id="accordion"> | |||||
<!-- we are adding the .panel class so bootstrap.js collapse plugin detects it --> | |||||
<div class="panel box box-primary"> | |||||
<div class="box-header with-border"> | |||||
<h4 class="box-title"> | |||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne"> | |||||
python中经典的四点透视变换方法的java实现。轻松实现图像的透视变换 | |||||
</a> | |||||
</h4> | |||||
</div> | |||||
<div id="collapseOne" class="panel-collapse collapse in"><!--class="panel-collapse collapse in"中的 in 控制展开 --> | |||||
<div class="box-body"> | |||||
<h4>参考资料:<br> | |||||
<a href="https://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example/"> | |||||
https://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example/</a> <br> | |||||
<a href="https://www.pyimagesearch.com/2016/03/21/ordering-coordinates-clockwise-with-python-and-opencv/"> | |||||
https://www.pyimagesearch.com/2016/03/21/ordering-coordinates-clockwise-with-python-and-opencv/</a> <br> | |||||
<a href="https://www.pyimagesearch.com/2014/09/01/build-kick-ass-mobile-document-scanner-just-5-minutes/"> | |||||
https://www.pyimagesearch.com/2014/09/01/build-kick-ass-mobile-document-scanner-just-5-minutes/</a> <br> | |||||
</h4> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!-- /.box-body --> | |||||
<h4> 效果测试</h4> | |||||
<div class="box-body"> | |||||
<a class="btn btn-info" id="handle"><i class="fa fa-object-ungroup"></i>处理</a> | |||||
<a class="btn btn-info" id="reset"><i class="fa fa-refresh"></i>重置</a> | |||||
</div> | |||||
<div class="row"> | |||||
<div class="col-sm-8"> | |||||
<div class="box box-primary"> | |||||
<div class="box-header with-border"> | |||||
<h3 class="box-title">原图</h3> | |||||
<span class="label label-primary pull-right"><i class="fa fa-html5"></i></span> | |||||
</div><!-- /.box-header --> | |||||
<div class="box-body"> | |||||
<p>原文件。</p> | |||||
<img id="oldimg" src="" alt="原图" /> | |||||
</div><!-- /.box-body --> | |||||
</div><!-- /.box --> | |||||
</div><!-- /.col --> | |||||
<div class="col-sm-4"> | |||||
<div class="box box-danger"> | |||||
<div class="box-header with-border"> | |||||
<h3 class="box-title">处理后的图片</h3> | |||||
<span class="label label-danger pull-right"><i class="fa fa-database"></i></span> | |||||
</div><!-- /.box-header --> | |||||
<div class="box-body"> | |||||
<p>点击处理按钮后,将显示处理后的文件。</p> | |||||
<img id="newimg" src="" alt="处理后的图" /> | |||||
</div><!-- /.box-body --> | |||||
</div><!-- /.box --> | |||||
</div><!-- /.col --> | |||||
</div> | |||||
</body> | |||||
<script src="${ctxStatic}/plugins/bootstrap-slider/bootstrap-slider.js?t=${version}"></script> | |||||
<script src="${ctxStatic}/plugins/iCheck/icheck.js?t=${version}"></script> | |||||
</html> |