package com.nbsl.cv.utils;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.imageio.ImageIO;
import org.bytedeco.javacpp.BytePointer;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_core.MatExpr;
import org.bytedeco.javacpp.opencv_core.MatVector;
import org.bytedeco.javacpp.opencv_core.Point;
import org.bytedeco.javacpp.opencv_core.Point2d;
import org.bytedeco.javacpp.opencv_core.Point2f;
import org.bytedeco.javacpp.opencv_core.PointVector;
import org.bytedeco.javacpp.opencv_core.Rect;
import org.bytedeco.javacpp.opencv_core.RectVector;
import org.bytedeco.javacpp.opencv_core.RotatedRect;
import org.bytedeco.javacpp.opencv_core.Scalar;
import org.bytedeco.javacpp.opencv_core.Size;
import org.bytedeco.javacpp.opencv_imgcodecs;
import org.bytedeco.javacpp.opencv_imgproc;
import org.bytedeco.javacpp.opencv_objdetect.CascadeClassifier;
import org.bytedeco.javacpp.indexer.ByteArrayIndexer;
import org.bytedeco.javacpp.indexer.ByteIndexer;
import org.bytedeco.javacpp.indexer.DoubleArrayIndexer;
import org.bytedeco.javacpp.indexer.DoubleIndexer;
import org.bytedeco.javacpp.indexer.IntIndexer;
import org.bytedeco.javacpp.indexer.IntRawIndexer;
import org.bytedeco.javacpp.indexer.UByteRawIndexer;
public class OpencvUtil {
private static final int BLACK = 0;
private static final int WHITE = 255;
public static Mat flow(Mat mat) {
// 灰度
mat = OpencvUtil.gray(mat);
// 二值化 此处绝定图片的清晰度
mat = OpencvUtil.binary(mat);
// 腐蚀 去除背景图片
mat = OpencvUtil.erode(mat, 1);
return mat;
}
/**
* 灰化处理
*
* @return
*/
public static Mat gray(Mat mat) {
Mat gray = new Mat();
opencv_imgproc.cvtColor(mat, gray, opencv_imgproc.COLOR_BGR2GRAY, 1);
return gray;
}
/**
* 增强对比
* @param mat
* @return
*/
public static Mat splitBGR(Mat mat) {
MatVector splitBGR = new MatVector();
opencv_core.split(mat, splitBGR);
for (int i = 0; i<mat.channels(); i++){
opencv_imgproc.equalizeHist(splitBGR.get(i), splitBGR.get(i));
}
opencv_core.merge(splitBGR, mat);
return mat;
}
/**
* 二值化处理
*参数1:InputArray类型的src,输入图像,填单通道,单8位浮点类型Mat即可。
参数2:函数运算后的结果存放在这。即为输出图像(与输入图像同样的尺寸和类型)。
参数3:预设满足条件的最大值。
参数4:指定自适应阈值算法。可选择ADAPTIVE_THRESH_MEAN_C 或 ADAPTIVE_THRESH_GAUSSIAN_C两种。(具体见下面的解释)。
参数5:指定阈值类型。可选择THRESH_BINARY或者THRESH_BINARY_INV两种。(即二进制阈值或反二进制阈值)。
参数6:表示邻域块大小,用来计算区域阈值,一般选择为3、5、7......等。
参数7:参数C表示与算法有关的参数,它是一个从均值或加权均值提取的常数,可以是负数。(具体见下面的解释)。
* @return
*/
public static Mat binary(Mat mat) {
Mat binary = new Mat();
// 高斯平滑滤波器卷积降噪
//opencv_imgproc.GaussianBlur(mat, mat, new Size(3,3), 0);
opencv_imgproc.adaptiveThreshold(mat, binary, 255, opencv_imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,
opencv_imgproc.THRESH_BINARY_INV, 7, 10);
return binary;
}
/**
* 模糊处理
*
* @param mat
* @return
*/
public static Mat blur(Mat mat) {
Mat blur = new Mat();
opencv_imgproc.blur(mat, blur, new Size(5, 5));
return blur;
}
/**
* 膨胀
*
* @param mat
* @return
*/
public static Mat dilate(Mat mat, int size) {
Mat dilate = new Mat();
Mat element = opencv_imgproc.getStructuringElement(opencv_imgproc.MORPH_RECT, new Size(size, size));
// 膨胀
opencv_imgproc.dilate(mat, dilate, element); // , new Point(-1, -1), 1
return dilate;
}
/**
* 腐蚀
*
* @param mat
* @return
*/
public static Mat erode(Mat mat, int size) {
Mat erode = new Mat();
Mat element = opencv_imgproc.getStructuringElement(opencv_imgproc.MORPH_RECT, new Size(size, size));
// 腐蚀
opencv_imgproc.erode(mat, erode, element);// , new Point(-1, -1), 1
return erode;
}
/**
* 边缘检测
*
* @param mat
* @return
*/
public static Mat carry(Mat mat) {
Mat dst = new Mat();
// 高斯平滑滤波器卷积降噪
opencv_imgproc.GaussianBlur(mat, dst, new Size(3, 3), 0);
// 边缘检测
//opencv_imgcodecs.imwrite("F:/face/1.jpg", dst);
opencv_imgproc.Canny(mat, dst, 50, 150);
//opencv_imgcodecs.imwrite("F:/face/2.jpg", dst);
return dst;
}
/**
* 轮廓检测
*定义轮廓的检索模式,取值如下:
CV_RETR_EXTERNAL:只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略;
CV_RETR_LIST:检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,具体下文会讲到;
CV_RETR_CCOMP: 检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层;
CV_RETR_TREE: 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。
参数5:定义轮廓的近似方法,取值如下:
CV_CHAIN_APPROX_NONE:保存物体边界上所有连续的轮廓点到contours向量内;
CV_CHAIN_APPROX_SIMPLE:仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留;
CV_CHAIN_APPROX_TC89_L1:使用teh-Chinl chain 近似算法;
CV_CHAIN_APPROX_TC89_KCOS:使用teh-Chinl chain 近似算法。
* @param mat
* @return
*/
public static MatVector findContours(Mat mat) {
MatVector contours = new MatVector();
Mat hierarchy = new Mat();
/*opencv_imgproc.findContours(mat, contours, hierarchy, opencv_imgproc.RETR_LIST,
opencv_imgproc.CHAIN_APPROX_SIMPLE);*/
opencv_imgproc.findContours(mat, contours, hierarchy, opencv_imgproc.RETR_LIST,
opencv_imgproc.CHAIN_APPROX_SIMPLE);
return contours;
}
/**
* 清除小面积轮廓
*
* @param mat
* @param size
* @return
*/
public static Mat drawContours(Mat mat, int size) {
MatVector cardContours = OpencvUtil.findContours(mat);
for (int i = 0; i < cardContours.size(); i++) {
double area = OpencvUtil.area(cardContours.get(i));
if (area < size) {
opencv_imgproc.drawContours(mat, cardContours, i, new opencv_core.Scalar(0, 0));
}
}
return mat;
}
/**
* 人脸识别
*
* @param mat
* @return
*/
public static RectVector face(Mat mat) throws Exception {
File file = org.springframework.util.ResourceUtils
.getFile("classpath:idcard\\haarcascades\\haarcascade_frontalface_alt.xml");
CascadeClassifier faceDetector = new CascadeClassifier(file.getAbsolutePath());
// 在图片中检测人脸
RectVector faceDetections = new RectVector();
// 指定人脸识别的最大和最小像素范围
Size minSize = new Size(100, 100);
Size maxSize = new Size(500, 500);
// 参数设置为scaleFactor=1.1f, minNeighbors=4, flags=0 以此来增加识别人脸的正确率
faceDetector.detectMultiScale(mat, faceDetections, 1.1f, 4, 0, minSize, maxSize);
if (faceDetections != null && faceDetections.size() > 0L) {
// 在每一个识别出来的人脸周�