当前位置: 首页 > news >正文

Java+OpenCV实现图片切割

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库,由英特尔公司发起并参与开发,首次发布于2000年。它现在由OpenCV基金会管理,是计算机视觉领域最受欢迎和广泛使用的库之一。

原理说明

图像在内存中就是一个连续的或逐行存储的多维数组,只要算出要保留的那一段数据在数组中的起始位置与长度,把它拷出来就完成了切割。下面对这个原理进行说明。

1、内存布局:Mat = 元数据 + 数据指针

  • OpenCV 的 cv::Mat(或 Python 里 numpy.ndarray 包装成的 Mat)里真正保存像素的是uchar*data 这个指针。
  • 对于 8-bit 3 通道图像,每行占 width*3 字节;如果宽不是 4 的倍数,OpenCV 会自动在行尾补 0 做 4-byte对齐,得到 step = width*3 + padding
  • 因此,只要知道 (x, y) 在数组里的偏移量,就能 O(1) 定位到那一行、那一列的像素: offset = y * step + x * channels

2、切片操作:构造“新头 + 旧身”的轻量 Mat

  • cv::Mat 有一个构造函数

    Mat(const Mat& m, const Rect& roi)它不会复制像素数据,而是把新 Mat 的 data 指针指向原图对应偏移位置,并重新填写 rows/cols/step/flags 等头信息。

  • 因此 img(Rect(x,y,w,h)) 得到的仍然指向同一块内存,只是“看起来”变小了;若后续还要对原图操作,需要 clone()copyTo() 做一次深拷贝。

3、逐像素复制(只有必要时才做)

如果我们用 img(roi).copyTo(cropped),OpenCV 内部就走 memcpy 逐行拷贝:

for i = 0..h-1memcpy(dst + i*dst.step,src + (y0+i)*src.step + x0*cn,w*cn);

复杂度 O(h·w·c),内存连续时效率极高。

一、 环境搭建

安装JDK

版本大于jdk8,用于支持Java基础程序。

安装OpenCV(windows)

方法一: 直接下载
下载
https://github.com/opencv/opencv/releases/tag/4.5.1
解压后得到opencv_videoio_ffmpeg451_64.dll文件,放到C:\Windows\System32
方法二: 使用pip下载

# 清华镜像加速
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python opencv-contrib-python

验证是否安装成功

python -c "import cv2,sys;print(cv2.__version__,sys.version.split()[0])"
# 输出示例:4.10.0 3.11.5

安装OpenCV(linux)

方法一: 通过apt下载

sudo apt update
sudo apt install python3-pip python3-venv -y
python3 -m venv ~/cv_env
source ~/cv_env/bin/activate
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python opencv-contrib-python

方法二: 下载源码编译
安装依赖

sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential cmake ninja-build \git pkg-config libjpeg-dev libpng-dev libtiff-dev \libavcodec-dev libavformat-dev libswscale-dev \libgtk-3-dev libcanberra-gtk3-module \python3-dev python3-numpy

下载、编译

git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git
cd opencv
cmake -B build -G Ninja \-DCMAKE_BUILD_TYPE=Release \-DCMAKE_INSTALL_PREFIX=/usr/local \-DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules \-DWITH_CUDA=ON \-DCUDA_ARCH_BIN=7.5,8.6
cmake --build build --parallel $(nproc)
sudo cmake --install build
sudo ldconfig   # 刷新动态库缓存

验证

pkg-config --modversion opencv4
python3 -c "import cv2; print(cv2.getBuildInformation())" | head -20

二、代码工程配置

在项目的pom.xml文件中添加Seata的依赖,如下所示:

        <dependency><groupId>org.openpnp</groupId><artifactId>opencv</artifactId><version>4.5.1-2</version></dependency>

三、 服务接入

这里写的方法用于实现将一张图片平均分割成12张子图,并上传minio存储

    static {System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // 加载 OpenCV}// 上传并切割上传public List<String> uploadWithSplitPic(MultipartFile[] files) throws IOException {List<String> fileNames = new ArrayList<>();List<String> fileIds = new ArrayList<>();int parts = 12for (MultipartFile file : files) {this.dealImg(file);// 切割图片并上传List<MultipartFile> splitFiles = splitImage(file, parts);for (MultipartFile splitFile : splitFiles) {String splitFileMd5 = calculateMd5(splitFile);FileInfo splitFileInfo = uploadFile(splitFile, splitFileMd5);fileNames.add(splitFile.getOriginalFilename());fileIds.add(splitFileInfo.getId());}}return fileIds;}private String calculateMd5(MultipartFile file) throws IOException {Digester digester = new Digester(DigestAlgorithm.MD5);return digester.digestHex(file.getInputStream());}private FileInfo uploadFile(MultipartFile file, String md5) throws IOException {FileInfo fileInfo = new FileInfo();fileInfo.setFile(file);fileInfo.setStoreGroup(minioBucketName);fileInfo.setFilePath(FILE_UPLOAD_PATH);fileInfo.setMd5(md5);fileInfo.setCustomPath("/");return fileService.uploadFile(fileInfo);}public static List<MultipartFile> splitImage(MultipartFile file , int p) throws IOException {// 读取图片Mat src = Imgcodecs.imdecode(new MatOfByte(file.getBytes()), Imgcodecs.IMREAD_UNCHANGED);if (src.empty()) {throw new IOException("无法加载图片");}// 行列数int rows = (int) Math.sqrt(p);int cols = (int) Math.ceil((double) p / rows);int pieceWidth = src.cols() / cols;int pieceHeight = src.rows() / rows;List<MultipartFile> parts = new ArrayList<>();for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {// 切割子图Rect roi = new Rect(j * pieceWidth, i * pieceHeight, pieceWidth, pieceHeight);Mat subImage = new Mat(src, roi);// 转换为 MultipartFileparts.add(convertMatToMultipartFile(subImage, file.getOriginalFilename()));}}return parts;}/*** 将 Mat 转换为 MultipartFile*/private static MultipartFile convertMatToMultipartFile(Mat image, String originalFilename) throws IOException {MatOfByte matOfByte = new MatOfByte();// 分割后的图片暂定为jpgImgcodecs.imencode(".jpg", image, matOfByte);ByteArrayInputStream inputStream = new ByteArrayInputStream(matOfByte.toArray());return new MockMultipartFile(originalFilename, originalFilename, "image/jpeg", inputStream);}

四、 结语

OpenCV 切图就是指针偏移、零拷贝,代码简单,执行的速度也比较快,省内存且无缝衔接后续的算法;但只能轴向矩形,且默认与原图共享内存,一改 ROI 母图同步变,需手动 .clone() 才能独立。

http://www.dtcms.com/a/519792.html

相关文章:

  • Linux云计算基础篇(24)-PXE批量安装和Kickstart工具
  • 从零搭建 RAG 智能问答系统 6:Text2SQL 与工作流实现数据库查询
  • 创建Django项目
  • 注册个人网站的方法建设企业网站费用
  • 初识C语言13.自定义类型(联合体与枚举)
  • WebRTC入门指南:实时通信零基础
  • 深圳外贸营销型网站建设引擎搜索网站
  • Django 表单验证详解Form
  • k8s相关学习
  • 【2026计算机毕业设计】基于Django的社区婴幼儿预防接种系统
  • D030知识图谱科研文献论文推荐系统vue+django+Neo4j的知识图谱|论文本文相似度推荐|协同过滤
  • pg库、MySQL库和sqlite3基本操作
  • Android Studio新手开发第三十天
  • 住房建设部官方网站公示公告手机网站内容模块
  • 网站建设 数据库连接网站建设公司软件开
  • 深入理解栈与队列:核心特性与实战应用
  • 如何建一个免费的网站南昌做网站优化哪家好
  • 机器学习概念,算法原理及应用
  • Pytorch常用层总结
  • 【Deepseek OCR】重磅测试,mac环境下的体验【本人已经本地实验成功】
  • 轻量化(Lightweight)概念
  • [人工智能-大模型-58]:模型层技术 - 深度神经网络的本质是一个复杂的复合数学函数
  • 【小白笔记】将十进制数(Decimal)转换为二进制数(Binary),并计算二进制表示中“1”的个数
  • 长春怎么注册网站平台wordpress 视频列表
  • 【ReAcTable】面向表格问答任务的ReAct增强框架
  • Docker 部署 Elasticsearch 全流程手册
  • React 集成Redux数据状态管理 数据共享 全局共享
  • Docker与Nginx:现代Web部署的完美二重奏
  • 【JUnit实战3_08】第四章:从 JUnit 4 迁移到 JUnit 5
  • React 03