https://github.com/opencv/opencv/releases
下载这个
下面的exe也可以 这个exe是一个自解压文件
安装的时候选择目录的时候不用新建opencv
,在解压的时候会自动创建opencv
文件夹。
下载到服务器上
安装依赖
yum groupinstall -y "Development Tools"
sudo yum -y install epel-release cmake3 gtk2-devel libpng-devel jasper-devel openexr-devel libwebp-devel libjpeg-turbo-devel libtiff-devel tbb-devel eigen3-devel boost boost-thread boost-devel libv4l-devel
查看gcc版本
gcc -v
安装:
unzip opencv-4.6.0.zip
cd opencv-4.6.0 && mkdir build && cd build
cmake3 -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local/opencv4 \
-D OPENCV_GENERATE_PKGCONFIG=ON ..
然后输入下述命令进行编译:
make -j8
使用make -j4
或者make -j8
进行多线程编译,虽然速度快但是容易出问题。
使用make
如果中间如果因为特殊原因断了,可以使用make
命令再继续。
编译100%完成后最后输入下述命令进行安装:
make install
输入以下命令:
cd /etc/ld.so.conf.d/
sudo touch opencv.conf
sudo sh -c 'echo "/usr/local/opencv4/lib64" > opencv.conf'
sudo ldconfig
然后,复制.pc文件:
sudo cp -f /usr/local/opencv4/lib64/pkgconfig/opencv4.pc /usr/lib64/pkgconfig/opencv4.pc
注意,我安装的是4.6.0,生成的是opencv4.pc
,不是opencv.pc
测试一下:
pkg-config --modversion opencv4
注意
本文中使用的cmake3就不用再升级cmake了。
cmake需要3.5.1以上的版本
sudo yum install build-essential libssl-dev
wget http://www.cmake.org/files/v3.16/cmake-3.16.6.tar.gz
tar xf cmake-3.16.6.tar.gz
sudo chmod -R 777 cmake-3.16.6
cd cmake-3.16.6
./bootstrap
make
make install
通过yum命令移除原先的CMake。
yum remove cmake -y
建立目标版本CMake的软连接。
ln -s /usr/local/bin/cmake /usr/bin
查看版本
cmake --version
升级cmake的时候又报错
version `GLIBCXX_3.4.20‘ not found 解决方法
解决方法
su root
cd /usr/local/lib64
# 下载最新版本的libstdc.so_.6.0.26
sudo wget http://www.vuln.cn/wp-content/uploads/2019/08/libstdc.so_.6.0.26.zip
unzip libstdc.so_.6.0.26.zip
# 将下载的最新版本拷贝到 /usr/lib64
cp libstdc++.so.6.0.26 /usr/lib64
cd /usr/lib64
# 查看 /usr/lib64下libstdc++.so.6链接的版本
ls -l | grep libstdc++
可以看到
libstdc++.so.6 ->libstdc++.so.6.0.19
# 删除/usr/lib64原来的软连接libstdc++.so.6,删除之前先备份一份
sudo rm libstdc++.so.6
# 链接新的版本
sudo ln -s libstdc++.so.6.0.26 libstdc++.so.6
# 查看新版本,成功
strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX
yum install opencv opencv-devel opencv-python -y
pkg-config --modversion opencv
卸载
yum remove opencv opencv-devel opencv-python -y
sudo apt update
sudo apt install -y libopencv-dev python3-opencv
获取版本
python3 -c "import cv2; print(cv2.__version__)"
卸载
sudo apt remove -y libopencv-dev python3-opencv
https://github.com/opencv/opencv/releases
添加环境依赖
sudo apt install -y build-essential cmake git pkg-config libgtk-3-dev \
libavcodec-dev libavformat-dev libswscale-dev libv4l-dev \
libxvidcore-dev libx264-dev libjpeg-dev libpng-dev libtiff-dev \
gfortran openexr libatlas-base-dev python3-dev python3-numpy \
libtbb2 libtbb-dev libdc1394-22-dev libopenexr-dev \
libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev
cmake需要3.5.1以上的版本
查看cmake版本
cmake --version
安装:
unzip opencv-4.6.0.zip
cd opencv-4.6.0
mkdir build && cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local/opencv4 \
-D OPENCV_GENERATE_PKGCONFIG=ON ..
然后输入下述命令进行编译:
make -j12
使用make -j4
或者make -j8
进行多线程编译,虽然速度快但是容易出问题。
使用make
如果中间如果因为特殊原因断了,可以使用make
命令再继续。
编译100%完成后最后输入下述命令进行安装:
make install
输入以下命令:
cd /etc/ld.so.conf.d/
sudo touch opencv.conf
# 根据安装位置
sudo sh -c 'echo "/usr/local/opencv4/lib" > opencv.conf'
sudo ldconfig
然后,复制.pc文件:
sudo cp -f /usr/local/opencv4/lib/pkgconfig/opencv4.pc /usr/lib/pkgconfig/opencv4.pc
注意,我安装的是4.6.0,生成的是opencv4.pc
,不是opencv.pc
测试一下:
pkg-config --modversion opencv4
项目中添加jar
jar的位置在安装目录下build\java
的目录下。
下面两种方式任选其一即可。
推荐方式1,方式2在Linux上就失效了。
添加测试代码
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
public class Test01 {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void main(String[] args) {
System.out.println("Welcome to OpenCV " + Core.VERSION);
Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0));
System.out.println("OpenCV Mat: " + m);
Mat mr1 = m.row(1);
mr1.setTo(new Scalar(1));
Mat mc5 = m.col(5);
mc5.setTo(new Scalar(5));
System.out.println("OpenCV Mat data:\n" + m.dump());
}
}
配置运行时参数。
通过菜单Run->Edit Configurations...
打开Run/Debug Configurations
对话框。
在对话框窗口右侧,找到VM options
标签对应的文本框。
在文本框中填写参数
-Djava.library.path=D:\Tools\opencv\build\java\x64
看好自己电脑是64为就选x64,32位就选x86。
当然也可以直接把opencv_java455.dll
放在Java的bin目录下,这样也就不用配置java.library.path
。
D:\Tools\Java\jdk1.8.0_102\bin
这种方式就不用再指定java.library.path
了。
把jar和dll放到项目中。
代码中
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import java.net.URL;
public class Test01 {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
URL url = ClassLoader.getSystemResource("lib/opencv/opencv_java455.dll");
System.load(url.getPath());
}
public static void main(String[] args) {
System.out.println("Welcome to OpenCV " + Core.VERSION);
Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0));
System.out.println("OpenCV Mat: " + m);
Mat mr1 = m.row(1);
mr1.setTo(new Scalar(1));
Mat mc5 = m.col(5);
mc5.setTo(new Scalar(5));
System.out.println("OpenCV Mat data:\n" + m.dump());
}
}
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import utils.OpenCVUtil;
public class Test01 {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void main(String[] args) {
// 以灰度方式,读取图片
Mat img = Imgcodecs.imread("D:\\Pic\\0.png", Imgcodecs.IMREAD_GRAYSCALE);
Imgcodecs.imwrite("D:\\Pic\\1.png", img);
// 转成二值化图片
Mat img2 = new Mat();
Imgproc.threshold(img, img2, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
Imgcodecs.imwrite("D:\\Pic\\2.png", img2);
// 膨胀
Mat img3 = OpenCVUtil.eroding(img2);
Imgcodecs.imwrite("D:\\Pic\\3.png", img3);
}
}
如上就分别展示了
// 以灰度方式,读取图片
Mat img = Imgcodecs.imread("D:\\Pic\\0.png", Imgcodecs.IMREAD_GRAYSCALE);
Imgcodecs.imwrite("D:\\Pic\\1.png", img);
// 转成二值化图片
Mat img2 = new Mat();
Imgproc.threshold(img, img2, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
Imgcodecs.imwrite("D:\\Pic\\2.png", img2);
// 膨胀
Mat img3 = OpenCVUtil.eroding(img2);
Imgcodecs.imwrite("D:\\Pic\\3.png", img3);
Mat img01 = new Mat();
Imgproc.GaussianBlur(img, img01, new Size(1, 1), 10, 10);
Imgcodecs.imwrite("D:\\Pic\\img01.png", img01);
// 截取左上角四分之一区域
Rect rect = new Rect(0, 0, img2.cols() / 2, img2.rows() / 2);
Mat img4 = new Mat(img2, rect);
Imgcodecs.imwrite("D:\\Pic\\4.png", img4);
package utils.opencv;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.IOException;
import java.util.*;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
public class OpenCVUtil {
public static BufferedImage covertMat2Buffer(Mat mat) throws IOException {
long time1 = new Date().getTime();
// Mat 转byte数组
BufferedImage originalB = toBufferedImage(mat);
long time3 = new Date().getTime();
System.out.println("保存读取方法2转=" + (time3 - time1));
return originalB;
// ImageIO.write(originalB, "jpg", new File("D:\\test\\testImge\\ws2.jpg"));
}
public static byte[] covertMat2Byte(Mat mat) throws IOException {
long time1 = new Date().getTime();
// Mat 转byte数组
byte[] return_buff = new byte[(int) (mat.total() * mat.channels())];
Mat mat1 = new Mat();
mat1.get(0, 0, return_buff);
long time3 = new Date().getTime();
System.out.println(mat.total() * mat.channels());
System.out.println("保存读取方法2转=" + (time3 - time1));
return return_buff;
}
public static byte[] covertMat2Byte1(Mat mat) throws IOException {
long time1 = new Date().getTime();
MatOfByte mob = new MatOfByte();
Imgcodecs.imencode(".jpg", mat, mob);
long time3 = new Date().getTime();
// System.out.println(mat.total() * mat.channels());
System.out.println("Mat转byte[] 耗时=" + (time3 - time1));
return mob.toArray();
}
public static BufferedImage toBufferedImage(Mat m) {
int type = BufferedImage.TYPE_BYTE_GRAY;
if (m.channels() > 1) {
type = BufferedImage.TYPE_3BYTE_BGR;
}
int bufferSize = m.channels() * m.cols() * m.rows();
byte[] b = new byte[bufferSize];
m.get(0, 0, b); // get all the pixels
BufferedImage image = new BufferedImage(m.cols(), m.rows(), type);
final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(b, 0, targetPixels, 0, b.length);
return image;
}
/**
* 腐蚀膨胀是针对于白色区域来说的,腐蚀即腐蚀白色区域
* 腐蚀算法(黑色区域变大)
*
* @param source
* @return
*/
public static Mat eroding(Mat source) {
return eroding(source, 1);
}
public static Mat eroding(Mat source, double erosion_size) {
Mat resultMat = new Mat(source.rows(), source.cols(), source.type());
Mat element = Imgproc.getStructuringElement(
Imgproc.MORPH_RECT,
new Size(erosion_size + 1, erosion_size + 1)
);
Imgproc.erode(source, resultMat, element);
return resultMat;
}
/**
* 腐蚀膨胀是针对于白色区域来说的,膨胀是膨胀白色区域
* 膨胀算法(白色区域变大)
*
* @param source
* @return
*/
public static Mat dilation(Mat source) {
return dilation(source, 1);
}
/**
* 腐蚀膨胀是针对于白色区域来说的,膨胀是膨胀白色区域
*
* @param source
* @param dilation_size 膨胀因子2*x+1 里的x
* @return Mat
*/
public static Mat dilation(Mat source, double dilation_size) {
Mat resultMat = new Mat(source.rows(), source.cols(), source.type());
Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(2 * dilation_size + 1,
2 * dilation_size + 1));
Imgproc.dilate(source, resultMat, element);
return resultMat;
}
}
package utils.opencv;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import org.opencv.utils.Converters;
import java.util.Arrays;
import java.util.List;
/**
* 透视变换工具类
* 因为我透视变换做的也不是很好,就仅提供一个大概的函数...
*/
public class WarpPerspectiveUtils {
/**
* 透视变换
*
* @param src
* @param points
* @return
*/
public static Mat warpPerspective(Mat src, Point[] points) {
// 点的顺序[左上 ,右上 ,右下 ,左下]
List<Point> listSrcs = Arrays.asList(
points[0],
points[1],
points[2],
points[3]
);
Mat srcPoints = Converters.vector_Point_to_Mat(listSrcs, CvType.CV_32F);
List<Point> listDsts = Arrays.asList(
new Point(0, 0),
new Point(src.width(), 0),
new Point(src.width(), src.height()),
new Point(0, src.height())
);
Mat dstPoints = Converters.vector_Point_to_Mat(listDsts, CvType.CV_32F);
Mat perspectiveMmat = Imgproc.getPerspectiveTransform(dstPoints, srcPoints);
Mat dst = new Mat();
Imgproc.warpPerspective(
src,
dst,
perspectiveMmat,
src.size(),
Imgproc.INTER_LINEAR + Imgproc.WARP_INVERSE_MAP,
1,
new Scalar(0)
);
return dst;
}
}
package utils.opencv;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.imgproc.Imgproc;
import java.util.Vector;
/**
* 轮廓工具类
*/
public class ContoursUtils {
/**
* 获取图片的四个顶点
*
* @param img
* @return
*/
public static Point[] getAllPoints(Mat img) {
Point[] potArr = new Point[4];
for (int i = 0; i < 4; i++) {
potArr[i] = new Point(-1, -1);
}
int[] spaceArr = new int[]{-1, -1, -1, -1};
int cols = img.cols();
int rows = img.rows();
int x1 = cols / 3;
int x2 = cols * 2 / 3;
int y1 = rows / 3;
int y2 = rows * 2 / 3;
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
if (x > x1 && x < x2 && y > y1 && y < y2) {
continue;
}
double[] darr = img.get(y, x);
if (darr != null && darr.length >= 1 && darr[0] == 0) {
if (spaceArr[0] == -1) {
potArr[0].x = x;
potArr[0].y = y;
potArr[1].x = x;
potArr[1].y = y;
potArr[2].x = x;
potArr[2].y = y;
potArr[3].x = x;
potArr[3].y = y;
spaceArr[0] = getSpace(0, 0, x, y);
spaceArr[1] = getSpace(cols, 0, x, y);
spaceArr[2] = getSpace(cols, rows, x, y);
spaceArr[3] = getSpace(0, rows, x, y);
} else {
int s0 = getSpace(0, 0, x, y);
int s1 = getSpace(cols, 0, x, y);
int s2 = getSpace(cols, rows, x, y);
int s3 = getSpace(0, rows, x, y);
if (s0 < spaceArr[0]) {
spaceArr[0] = s0;
potArr[0].x = x;
potArr[0].y = y;
}
if (s1 < spaceArr[1]) {
spaceArr[1] = s1;
potArr[1].x = x;
potArr[1].y = y;
}
if (s2 < spaceArr[2]) {
spaceArr[2] = s2;
potArr[2].x = x;
potArr[2].y = y;
}
if (s3 < spaceArr[3]) {
spaceArr[3] = s3;
potArr[3].x = x;
potArr[3].y = y;
}
}
}
}
}
return potArr;
}
/**
* 轮廓识别,使用最外轮廓发抽取轮廓RETR_EXTERNAL,轮廓识别方法为CHAIN_APPROX_SIMPLE
*
* @param source 传入进来的图片Mat对象
* @return 返回轮廓结果集
*/
public static Vector<MatOfPoint> findContours(Mat source) {
Mat rs = new Mat();
/**
* 定义轮廓抽取模式
*RETR_EXTERNAL:只检索最外面的轮廓;
*RETR_LIST:检索所有的轮廓,并将其放入list中;
*RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
*RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次。
*/
/**
* 定义轮廓识别方法
* 边缘近似方法(除了RETR_RUNS使用内置的近似,其他模式均使用此设定的近似算法)。可取值如下:
*CV_CHAIN_CODE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
*CHAIN_APPROX_NONE:将所有的连码点,转换成点。
*CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。
*CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:使用the flavors of Teh-Chin chain近似算法的一种。
*LINK_RUNS:通过连接水平段的1,使用完全不同的边缘提取算法。使用CV_RETR_LIST检索模式能使用此方法。
*/
Vector<MatOfPoint> contours = new Vector<MatOfPoint>();
Imgproc.findContours(
source,
contours,
rs,
Imgproc.RETR_LIST,
Imgproc.CHAIN_APPROX_SIMPLE
);
return contours;
}
/**
* 计算两点之间的距离
*
* @param x1
* @param y1
* @param x2
* @param y2
* @return
*/
private static int getSpace(int x1, int y1, int x2, int y2) {
int xspace = Math.abs(x1 - x2);
int yspace = Math.abs(y1 - y2);
return (int) Math.sqrt(Math.pow(xspace, 2) + Math.pow(yspace, 2));
}
}
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import utils.opencv.ContoursUtils;
import utils.opencv.OpenCVUtil;
import utils.opencv.WarpPerspectiveUtils;
import java.util.Vector;
public class Test01 {
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
public static void main(String[] args) {
String basepath = "D:\\Project\\Java\\opencv-demo01\\pic\\";
// 以灰度方式,读取图片
Mat img = Imgcodecs.imread(basepath + "0.jpg", Imgcodecs.IMREAD_GRAYSCALE);
Imgcodecs.imwrite(basepath + "1.png", img);
// 转成二值化图片
Mat img2 = new Mat();
Imgproc.threshold(img, img2, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
Imgcodecs.imwrite(basepath + "2.png", img2);
// 透视变形
Mat img3 = WarpPerspectiveUtils.warpPerspective(img2, ContoursUtils.getAllPoints(img2));
Imgcodecs.imwrite(basepath + "3.png", img3);
// 膨胀
Mat img4 = OpenCVUtil.eroding(img3);
Imgcodecs.imwrite(basepath + "4.png", img4);
// 截取选择题区域
Rect rect = new Rect(68, 834, 1536, 220);
Mat img5 = new Mat(img4, rect);
Imgcodecs.imwrite(basepath + "5.png", img5);
// 获取边界
Vector<MatOfPoint> rectVec = ContoursUtils.findContours(img5);
Vector<MatOfPoint> rectVec2 = new Vector<>();
for (MatOfPoint matOfPoint : rectVec) {
Rect rect2 = Imgproc.boundingRect(matOfPoint);
if (rect2.width > 36 && rect2.height > 20 && rect2.width < 50 && rect2.height < 40) {
rectVec2.add(matOfPoint);
}
}
Mat img6 = new Mat(img5.rows(), img5.cols(), CvType.CV_8UC3, new Scalar(255, 255, 255));
Imgproc.drawContours(img6, rectVec2, -1, new Scalar(0, 0, 255), 1);
Imgcodecs.imwrite(basepath + "6.png", img6);
}
}
String basePath = "D:\\Project\\Java\\opencv-demo01\\pic\\";
Scalar bgColor = new Scalar(255, 255, 255, 0); // B G R 0 白色
Scalar color = new Scalar(0, 0, 255, 0); // B G R 0 红色
Mat img01 = new Mat(new Size(400, 500), CvType.CV_8UC3, bgColor);
Imgproc.line(
img01,
new Point(11, 22),
new Point(220, 330),
color,
1,
Imgproc.LINE_AA
);
Imgcodecs.imwrite(basePath + "line.png", img01);
说明
参数 | 解释 |
---|---|
InputOutPutArray img | 在 img 图像上绘制 |
Point pt1 | 端点1 |
Point pt2 | 端点2 |
Scalar& color | 颜色 |
int thickness | 线条厚度 |
lineType | 线条边缘类型(LINE_4(边缘像素采用4连通,即上下左右),LINE_8(边缘像素采用8连通,即上下左右还有四个对角),LINE_AA(边缘像素采用高斯滤波,抗锯齿)) |
String basePath = "D:\\Project\\Java\\opencv-demo01\\pic\\";
Scalar bck = new Scalar(255, 255, 255, 0); // B G R 0 白色
Scalar scalar = new Scalar(0, 0, 255, 0); // B G R 0 红色
Mat img01 = new Mat(new Size(400, 500), CvType.CV_8UC3, bck);
Imgproc.ellipse(img01, new Point(256, 256), new Size(100, 50), 0, 0, 360, scalar);
Imgcodecs.imwrite(basePath + "ellipse.png", img01);
String basePath = "D:\\Project\\Java\\opencv-demo01\\pic\\";
Scalar bck = new Scalar(255, 255, 255, 0); // B G R 0 白色
Scalar scalar = new Scalar(0, 0, 255, 0); // B G R 0 红色
Mat img01 = new Mat(new Size(400, 500), CvType.CV_8UC3, bck);
Imgproc.rectangle(img01, new Point(100, 20), new Point(310, 148), scalar);
Imgcodecs.imwrite(basePath + "rectangle.png", img01);
String basePath = "D:\\Project\\Java\\opencv-demo01\\pic\\";
Scalar bck = new Scalar(255, 255, 255, 0); // B G R 0 白色
Scalar scalar = new Scalar(0, 0, 255, 0); // B G R 0 红色
Mat img01 = new Mat(new Size(400, 500), CvType.CV_8UC3, bck);
Imgproc.circle(img01, new Point(100, 100), 63, scalar);
Imgcodecs.imwrite(basePath + "circle.png", img01);
String basePath = "D:\\Project\\Java\\opencv-demo01\\pic\\";
Scalar bck = new Scalar(255, 255, 255, 0); // B G R 0 白色
Scalar scalar = new Scalar(0, 0, 255, 0); // B G R 0 红色
Mat img01 = new Mat(new Size(400, 500), CvType.CV_8UC3, bck);
Imgproc.putText(
img01,
"Hello Word",
new Point(10, 100),
Imgproc.FONT_HERSHEY_SIMPLEX,
2,
scalar,
2,
Imgproc.LINE_AA,
false
);
Imgcodecs.imwrite(basePath + "text.png", img01);
要将文本放入图像中,需要指定以下内容。
文字的左下角
)。