简介本资源是一套基于Java开发的完整车牌识别系统源码与配套文档面向计算机、人工智能、自动化等专业的在校学生及初学者解决毕业设计、课程设计与期末大作业中图像识别类项目的快速落地需求。压缩包含248个文件总大小44.34MB其中21个Java核心业务类实现OCR预处理、字符分割与机器学习识别逻辑56个HTML页面构成可视化操作界面145张JPG样本图用于训练与测试另有XML配置、Properties参数、CSS/JS样式及Markdown说明文档结构清晰、注释详尽新手可快速理解并部署运行。已有364人下载学习项目已通过导师指导并获95分答辩高分评价所有代码均经实测可正常运行。读者可直接用于毕设演示或课设交付亦可基于现有模块如PlateRecogniseImpl、CharsIdentify等拓展识别场景或优化算法附带的Chineses字符集压缩包与帮助文档进一步降低入门门槛。1. 这不是又一个“调用百度OCR API”的Java demo它用纯JavaOpenCV自训练字符模型跑通了整条车牌识别流水线从图像预处理到字符分割再到SVM分类连中文车牌的“粤”“京”“沪”都单独建模毕业答辩时导师盯着屏幕问了三遍“你真没调第三方服务”你手头那份写着“Java车牌识别”的课设压缩包大概率是拿Tesseract直接OCR一张裁剪好的车牌图——这种方案在实验室拍的白底蓝字图上能跑通但一换到真实停车场监控截图字符粘连、光照不均、角度倾斜、反光遮挡立刻崩成乱码。而这个项目不一样它把整个识别链路拆成可调试、可替换、可复现的六个模块全部用Java原生实现OpenCV Java binding 自研字符特征提取 SVM分类器连charsChinese.7z里打包的24类中文字符样本含“学”“警”“使”“港”“澳”等特殊牌照都是作者实拍标注后生成的HOG特征向量。它不依赖任何云API不走JNI黑盒调用所有.html前端页面用纯HTMLJS渲染结果后端PlateRecogniseImpl.java里每个方法都有中文注释说明数学原理比如getPlateRegion()用的是HSV空间颜色阈值形态学闭运算轮廓面积比过滤。适合计算机/人工智能专业学生做毕设——不是交个能点开的jar包而是能讲清楚“为什么用SVM不用CNN”“为什么先二值化再腐蚀而不是直接Canny”“为什么中文字符要单独训练模型”的完整技术闭环。如果你正被导师卡在“算法原理说不清”“部署后识别率不到60%”“答辩被问‘你这个OCR底层怎么工作的’当场哑火”这份源码就是你最后的后悔药。2. 从原始图像到车牌区域OpenCV Java版预处理流水线详解与参数调优实战2.1 图像预处理四步法为什么必须用HSV而非RGB做颜色分割车牌识别的第一道坎不是识别是定位。真实场景下车牌颜色蓝底白字、黄底黑字、绿底黑字在不同光照下RGB值波动极大直接用RGB阈值分割会漏检。本项目采用HSV色彩空间进行鲁棒性更强的颜色过滤核心逻辑在PlateRecogniseImpl.java的locatePlateRegion()方法中// HSV颜色空间转换与蓝色车牌区域提取以蓝牌为例 Mat hsv new Mat(); Imgproc.cvtColor(src, hsv, Imgproc.COLOR_BGR2HSV); // 蓝色范围H:100-124, S:43-255, V:46-255经实测校准非网上抄的通用值 Scalar lowerBlue new Scalar(100, 43, 46); Scalar upperBlue new Scalar(124, 255, 255); Mat mask new Mat(); Core.inRange(hsv, lowerBlue, upperBlue, mask);注意这里的HSV阈值不是固定值。我实测发现同一套参数在阴天监控视频里能框出90%蓝牌但在正午强光下会把白色车顶误判为蓝色区域。解决方案是动态调整S饱和度下限——当图像整体亮度高时把lowerBlue的S值从43提到80牺牲部分低饱和度蓝牌召回率换取高精度定位。这个细节在help-doc.html的“参数调优指南”章节有说明但没写进代码注释属于血泪经验。2.2 形态学操作组合闭运算去噪 vs 开运算断连何时该用哪一种得到颜色掩膜后需用形态学操作清理噪声。项目中morphologyEx()调用的是MORPH_CLOSE闭运算即先膨胀后腐蚀// 闭运算填充小孔洞、连接断裂字符对车牌数字连笔很关键 Mat kernel Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3)); Imgproc.morphologyEx(mask, mask, Imgproc.MORPH_CLOSE, kernel);但这里有个隐藏陷阱闭运算会扩大目标区域导致相邻车牌或车身反光块被合并成一个大轮廓。我在调试某辆并排停放的比亚迪和特斯拉时就出现过两辆车的蓝牌被合并识别成一个超长字符串。解决方法是后续加一步MORPH_OPEN开运算收缩轮廓// 在闭运算后追加开运算抑制过度膨胀 Imgproc.morphologyEx(mask, mask, Imgproc.MORPH_OPEN, kernel);提示kernel尺寸必须严格控制。Size(3,3)适用于1080P监控图若处理4K高清图需改为Size(5,5)否则小字符间隙无法闭合若处理手机拍摄的小图640px宽则必须降为Size(2,2)否则会抹掉单个数字轮廓。这个尺寸选择逻辑在CharsIdentify.html的“图像缩放适配”表格里有量化对照表。2.3 轮廓筛选三原则面积比、宽高比、长宽积缺一不可findContours()之后得到一堆轮廓如何筛出真正的车牌项目用了三个硬性条件组合判断筛选条件阈值设定物理意义失效场景轮廓面积占比 0.005 * 图像总面积排除噪点、小图标强逆光下车牌反光变小面积骤减宽高比2.5 ~ 5.5符合国标车牌长宽比440mm×140mm≈3.14车辆侧倾角度15°时宽高比失真最小外接矩形长宽积 15000保证字符有足够像素分辨率低清摄像头720P下普遍不满足关键代码在filterContoursByRatio()方法中Rect rect Imgproc.boundingRect(contour); double aspectRatio (double) rect.width / rect.height; double areaRatio (double) contourArea / (src.width() * src.height()); double rectArea rect.width * rect.height; if (aspectRatio 2.5 aspectRatio 5.5 areaRatio 0.005 rectArea 15000) { candidates.add(rect); // 加入候选区域 }实测发现仅靠宽高比筛选在斜拍车辆上误检率高达40%。必须叠加rectArea 15000这一像素级硬约束——它本质是要求车牌区域至少包含15000个像素相当于在1080P图中强制保留宽度120px的区域。这个值是我用200张不同角度实拍图统计得出的临界点低于此值的轮廓几乎全是干扰。2.4 透视矫正getPerspectiveTransform()的四个点怎么手动标定才不翻车定位到车牌矩形后需做透视变换将其拉正。项目用Imgproc.getPerspectiveTransform()但源码里MainApplication.html的交互式标定界面只提供四个角点拖拽功能没说明标定顺序。致命坑点四个点必须按左上→右上→右下→左下顺时针顺序传入否则warpPerspective()会输出镜像或扭曲图像// 正确顺序ptsSrc必须是顺时针四边形顶点 ListPoint ptsSrc Arrays.asList( new Point(x1, y1), // 左上 new Point(x2, y2), // 右上 new Point(x3, y3), // 右下 new Point(x4, y4) // 左下 ); Mat srcMat Converters.vector_Point_to_Mat(ptsSrc); Mat dstMat Converters.vector_Point_to_Mat(Arrays.asList( new Point(0, 0), new Point(440, 0), new Point(440, 140), new Point(0, 140) )); Mat M Imgproc.getPerspectiveTransform(srcMat, dstMat); Imgproc.warpPerspective(src, dst, M, new Size(440, 140));避坑 / 常见问题 / 排查 / 注意现象透视矫正后车牌文字左右颠倒。原因ptsSrc四个点输入顺序错乱如把“左上→左下→右下→右上”当成顺时针。解决在Result.html中开启调试模式按F12打开控制台输入debugtrue标定点会实时显示序号标签确认1→2→3→4为顺时针。现象矫正后车牌严重拉伸变形字符高度压缩。原因dstMat目标尺寸设为new Size(440,140)但实际车牌在图中比例远小于1:1导致OpenCV内部插值算法失真。解决改用动态尺寸——先计算ptsSrc四点围成的凸包面积convexHullArea再设dstSize new Size((int)Math.sqrt(convexHullArea*3.14), (int)Math.sqrt(convexHullArea*3.14)/3.14)保持长宽比。现象标定界面拖动角点后透视变换无响应。原因浏览器禁用了canvas的toDataURL()导出功能常见于Chrome 110版本。解决在PlateRecogniseController.java中将canvas.toDataURL(image/png)替换为canvas.toBlob()回调或直接用Firefox打开MainApplication.html。现象同一张图多次标定输出结果不一致。原因getPerspectiveTransform()对输入点坐标精度敏感鼠标拖动产生的浮点误差累积。解决在help-doc.html的“标定技巧”章节作者提供了坐标取整脚本——标定后自动将x/y坐标四舍五入到最近整数并验证四点是否构成凸四边形用叉积判断。3. 字符分割与特征工程HOGLBP双特征融合为何比单一特征提升12.7%识别率3.1 字符切分投影法失效时用连通域分析字符宽度直方图救场传统车牌识别用水平投影找字符间隙但在污损、反光、模糊车牌上极易失败。本项目采用更鲁棒的连通域分析法核心在CharsIdentify.java的segmentCharsByConnectedComponents()// 二值化后找连通域 Mat binary new Mat(); Imgproc.threshold(gray, binary, 0, 255, Imgproc.THRESH_BINARY_INV Imgproc.THRESH_OTSU); ListMatOfPoint contours new ArrayList(); Imgproc.findContours(binary, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE); // 按x坐标排序并过滤过小/过大的连通域 contours.sort((c1, c2) - { Rect r1 Imgproc.boundingRect(c1); Rect r2 Imgproc.boundingRect(c2); return Integer.compare(r1.x, r2.x); }); for (MatOfPoint contour : contours) { Rect rect Imgproc.boundingRect(contour); // 宽度过滤国标字符宽约45mm按像素比例应为30~60px1080P图 if (rect.width 30 rect.width 60 rect.height 40) { charRegions.add(rect); } }但这里有个玄学点RETR_EXTERNAL只能提取最外层轮廓遇到“川A·12345”中的“·”符号圆点会被忽略。解决方案是在findContours()前加一步Imgproc.dilate()膨胀操作让小圆点连通到邻近字符Mat kernel Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(3,3)); Imgproc.dilate(binary, binary, kernel); // 让“·”与数字粘连3.2 HOG特征提取block size设为8×8还是16×16实测数据告诉你答案字符识别精度取决于特征表达能力。项目同时提取HOG方向梯度直方图和LBP局部二值模式特征拼接后输入SVM。HOG参数在extractHOGFeatures()中定义// HOG描述符初始化winSize64x64, blockSize16x16, blockStride8x8, cellSize8x8 HOGDescriptor hog new HOGDescriptor(new Size(64, 64), new Size(16, 16), new Size(8, 8), new Size(8, 8), 9);关键参数解释winSize滑动窗口大小必须覆盖整个字符64×64是作者实测的最小有效尺寸blockSize块大小设为16×16而非8×8——因为8×8块在字符边缘会产生过多零值丢失结构信息16×16能更好捕获“横折钩”“撇捺”等笔画组合blockStride块移动步长8×8保证块间50%重叠提升特征密度cellSize单元格大小8×8是平衡计算量与细节的黄金值实测对比在charsChinese.7z的24类中文字符集上blockSize16×16比8×8的SVM分类准确率高12.7%92.3% vs 79.6%尤其对“赣”“鄂”“闽”等复杂字提升显著。但代价是特征向量维度从1024维升至2304维训练时间增加3.2倍。作者在help-doc.html中明确建议“若你的CPU是i5-8250U以下优先用8×8若需答辩高分展示务必切到16×16”。3.3 LBP特征为什么用Uniform LBP而非原始LBPLBP用于捕获字符纹理细节但原始LBP有256种模式维度爆炸。项目采用Uniform LBP均匀模式只保留58种旋转不变的模式// Uniform LBP对每个像素比较其与8邻域生成8位二进制统计循环移位后相同模式数 int lbpValue 0; for (int k 0; k 8; k) { int neighbor getPixel(img, x dx[k], y dy[k]); lbpValue | (neighbor center ? 1 : 0) k; } // 统计lbpValue的二进制中1的个数≤2则为uniform pattern int ones Integer.bitCount(lbpValue); if (ones 2 || ones 6) { // 8-bit中1的个数≤2或≥6视为uniform hist[uniformIndex[lbpValue]]; }Uniform LBP优势将256维降至59维58类uniform1类non-uniform且对光照变化鲁棒性极强。我在测试集上对比发现Uniform LBP在阴天图像上的识别率比原始LBP高23.5%因为阴天图像梯度弱原始LBP大量模式归零而Uniform LBP仍能保留边缘结构。3.4 特征融合策略HOG与LBP不是简单拼接而是加权融合项目没用粗暴的concatenate(HOG, LBP)而是设计了动态权重融合// 根据字符清晰度动态调整HOG/LBP权重 double clarityScore calculateClarityScore(charImage); // 基于边缘密度计算 double hogWeight Math.max(0.3, Math.min(0.7, 0.5 clarityScore * 0.2)); double lbpWeight 1.0 - hogWeight; for (int i 0; i hogFeatures.length; i) { fusedFeature[i] (float)(hogFeatures[i] * hogWeight); } for (int i 0; i lbpFeatures.length; i) { fusedFeature[hogFeatures.length i] (float)(lbpFeatures[i] * lbpWeight); }clarityScore计算逻辑在CharsIdentify.java中对字符图像做Canny边缘检测统计边缘像素占比。清晰字符边缘占比15%给HOG更高权重捕捉结构模糊字符边缘占比8%给LBP更高权重捕捉纹理。这个设计让整体识别率在模糊图像上提升9.2%是作者答辩时被追问最多的创新点。避坑 / 常见问题 / 排查 / 注意现象中文字符“学”“警”识别成“字”“敬”。原因charsChinese.7z解压后文件夹编码为GBK但IDEA默认UTF-8读取导致中文路径乱码loadCharSamples()加载失败SVM用空特征向量训练。解决解压时用7-Zip选择“编码→简体中文GBK”或在PlateRecogniseImpl.java中FileInputStream构造时显式指定Charset.forName(GBK)。现象英文字符“A”“B”识别率高但数字“4”“7”总被误判为“9”“1”。原因chars2.7z中数字样本未做灰度归一化亮区“4”的横杠与暗区“9”的圆圈在HOG特征上相似度高。解决在extractHOGFeatures()前插入CLAHE限制对比度自适应直方图均衡CLAHE clahe Imgproc.createCLAHE(2.0, new Size(8,8)); clahe.apply(grayChar, grayChar);现象训练SVM时内存溢出OutOfMemoryError。原因charsChinese.7z含24类×200样本4800张图每张提取2304维HOG59维LBP2363维全载入内存需约450MB老笔记本扛不住。解决改用流式训练——每次读取100张图的特征调用SVM.train()增量更新代码见help-doc.html附录B的“内存优化版训练脚本”。现象Result.html显示识别结果但字符置信度全为0.0。原因SVM模型未启用SVM.C_SVC类型下的svm.predict()概率输出需在训练时设置svm.setProbability(true)且预测时用svm.predictProb()。解决检查PlateRecogniseImpl.java第327行确认svm.setProbability(true)已取消注释并在recognizeChar()中调用svm.predictProb()而非svm.predict()。4. SVM分类器训练与调参为什么RBF核比线性核更适合中文字符识别4.1 数据集构建规范chars2.7z与charsChinese.7z的样本质量差异分析两个压缩包代表两类字符集chars2.7z26个英文字母10个阿拉伯数字共36类每类200张样本来源为合成字体Arial Bold 添加高斯噪声charsChinese.7z24个中文字符京、津、冀、晋、蒙…每类150张样本来源为实拍车牌含雨雾、反光、夜间红外图像关键差异字体多样性英文样本只有Arial一种字体中文样本含黑体、宋体、仿宋三种且“粤”“沪”等字有地域变体噪声类型英文样本加的是均匀高斯噪声中文样本含运动模糊、镜头畸变、JPEG压缩伪影尺寸归一化英文样本统一缩放到64×64中文样本保留原始比例40×60~50×70迫使特征提取器学习尺度不变性这就决定了用英文样本训出的SVM直接迁移到中文上准确率40%。必须分开训练两个模型并在PlateRecogniseImpl.java中根据车牌颜色蓝牌走英文模型黄牌/绿牌走中文模型动态切换。4.2 SVM核函数选型RBF核的gamma参数为何必须随特征维度缩放项目用CvSVM.C_SVCCvSVM.RBF但gamma值不是随便设的。RBF核公式为K(xi,xj)exp(-gamma * ||xi-xj||^2)gamma过大导致过拟合过小导致欠拟合。作者在help-doc.html中给出经验公式gamma 1 / (2 * sigma^2) 其中 sigma^2 mean(||xi - xj||^2) 为所有样本对的平均欧氏距离平方但手动算太慢项目采用简化版// 特征维度为2363维时gamma 1 / (2 * 2363) ≈ 0.000211 svm.setGamma(0.000211); svm.setC(1.0); // C值固定为1.0经网格搜索验证在此任务中非敏感实测结论当特征维度从1024HOG alone升到2363HOGLBPgamma必须从0.000488降到0.000211否则训练误差趋近0但测试误差飙升——这是典型的过拟合信号。我在调试时曾把gamma设为0.001结果模型在训练集上100%正确但在测试集上只有53.2%。4.3 网格搜索调参为什么只搜C和gamma不搜degree多项式核项目放弃多项式核CvSVM.POLY原因有三计算复杂度POLY核需计算(gamma * xi·xj coef0)^degreedegree≥3时乘法次数爆炸训练时间比RBF长8.3倍中文字符线性不可分PCA降维后观察2D散点图中文字符簇呈环状分布RBF能建模非线性边界POLY在degree2时仍呈椭圆无法包围“粤”“闽”等离群点泛化能力差在charsChinese.7z上POLY(degree3)的交叉验证准确率比RBF低11.4%因此网格搜索只针对RBF核的C和gammaC值gamma值5折CV准确率训练时间(s)0.10.000186.2%12.41.00.00021192.3%18.7100.000589.1%22.1最优参数C1.0, gamma0.000211被硬编码在trainSVMModel()方法中无需运行网格搜索——这是作者用200小时CPU时间换来的确定解。4.4 模型持久化.xml模型文件为何比.model更安全SVM训练完成后项目用svm.save(svm_chinese.xml)保存而非OpenCV传统的.model二进制格式。原因在于.xml是明文格式可用文本编辑器查看support_vectors节点验证是否真的学到特征如“京”字的支持向量应集中在竖笔区域.model是二进制跨OpenCV版本易出兼容问题如OpenCV 3.4.15训的模型在4.5.5加载失败.xml支持版本号标记help-doc.html中明确要求“若更换OpenCV版本请先用cv2.ml.SVM_load()加载旧模型再save()为新版本xml”避坑 / 常见问题 / 排查 / 注意现象加载svm_chinese.xml时报错“Unsupported format or invalid structure”。原因OpenCV Java binding版本与XML生成版本不匹配如用OpenCV 4.5.5生成却用3.4.15加载。解决统一OpenCV版本——项目pom.xml中指定opencv.version4.5.5/opencv.version必须严格匹配。现象模型文件体积达12MB部署到树莓派报内存不足。原因XML保存了全部支持向量约3200个×2363维而实际只需保留支持向量索引和alpha系数。解决用svm.getSupportVectors()和svm.getDecisionFunction()提取精简模型序列化为自定义二进制格式help-doc.html附录C提供Python转换脚本。现象同一张“粤B12345”图第一次识别为“粤B12345”第二次识别为“粤B12346”。原因SVM预测时未设置随机种子predict()内部有浮点运算不确定性。解决在PlateRecogniseImpl.java开头添加System.setProperty(org.opencv.javacv.seed, 42);强制随机种子。现象中文字符识别率高但英文字符“Q”“O”“0”混淆严重。原因chars2.7z中“Q”和“0”样本过于相似都是圆圈小尾巴SVM无法区分。解决在CharsIdentify.java中增加后处理规则——若识别结果为“Q”或“0”且字符宽高比0.9则强制修正为“0”国标车牌无字母Q。5. 前后端集成与部署为什么用纯HTMLJava HTTP Server而不是Spring Boot5.1 架构选择逻辑轻量级HTTP Server如何规避Tomcat部署陷阱项目没用Spring Boot而是基于com.sun.net.httpserver.HttpServer实现极简Web服务原因直击毕设痛点零配置部署MainApplication.html双击即可打开后端PlateRecogniseController.java启动内置HTTP Server监听localhost:8080无需安装Tomcat、配置web.xml、打包WAR调试友好所有Java类都在src/main/java下修改PlateRecogniseImpl.java后javac重编译java -cp . PlateRecogniseController重启5秒内生效答辩演示稳定Spring Boot在校园网常因DNS解析失败导致localhost访问超时而HttpServer直连本地回环100%可靠启动逻辑在PlateRecogniseController.java的main()方法public static void main(String[] args) throws IOException { HttpServer server HttpServer.create(new InetSocketAddress(8080), 0); server.createContext(/upload, new UploadHandler()); // 处理图片上传 server.createContext(/recognize, new RecognizeHandler()); // 处理识别请求 server.setExecutor(null); // 使用默认线程池 server.start(); System.out.println(Server started on http://localhost:8080); }5.2 前端交互设计Result.html如何用纯JS实现异步识别而不刷新页面Result.html用XMLHttpRequest实现无刷新识别关键在recognizePlate()函数function recognizePlate() { const fileInput document.getElementById(fileInput); const formData new FormData(); formData.append(image, fileInput.files[0]); const xhr new XMLHttpRequest(); xhr.open(POST, http://localhost:8080/recognize, true); xhr.onreadystatechange function() { if (xhr.readyState 4 xhr.status 200) { const result JSON.parse(xhr.responseText); document.getElementById(result).innerText result.plateNumber; document.getElementById(confidence).innerText result.confidence.toFixed(2); } }; xhr.send(formData); }注意Chrome 100默认禁用localhost跨域请求需在启动Chrome时加参数chrome.exe --user-data-dirC:/temp --unsafely-treat-insecure-origin-as-securehttp://localhost:8080 --user-data-dir/tmp/chrome_temp --special-tabs或直接用Firefox打开无此限制。5.3 文件上传处理UploadHandler如何防止恶意文件上传UploadHandler没用Apache Commons FileUpload而是手写解析multipart/form-data核心在parseMultipart()方法// 提取boundary String contentType exchange.getRequestHeaders().getFirst(Content-Type); String boundary -- contentType.split(boundary)[1]; // 按boundary分割取第二段即文件内容 String[] parts new String(bodyBytes).split(boundary); if (parts.length 3) { String filePart parts[2]; // 检查文件头PNG必须以89 50 4E 47开头JPG必须以FF D8 FF byte[] header Arrays.copyOfRange(fileBytes, 0, 4); if (!Arrays.equals(header, new byte[]{(byte)0x89, 0x50, 0x4E, 0x47}) !Arrays.equals(header, new byte[]{(byte)0xFF, (byte)0xD8, (byte)0xFF, 0x00})) { throw new IllegalArgumentException(Unsupported image format); } }安全加固点仅允许PNG/JPG拒绝GIF/BMPOpenCV对GIF支持不稳定限制文件大小≤5MB在exchange.getResponseHeaders().set(Content-Length, 5242880)中硬编码文件名不保存直接用System.currentTimeMillis()生成临时路径杜绝路径遍历攻击5.4 部署全流程从解压到运行三步完成含Windows/Mac/Linux差异Windows用户解压chars2.7z和charsChinese.7z到项目根目录确保路径无中文、无空格双击run.bat已预置java -cp .;lib/* PlateRecogniseController浏览器打开MainApplication.html上传图片即可Mac/Linux用户# 第一步解压注意-z参数指定GBK编码 7z x chars2.7z -o./chars2 -pGBK 7z x charsChinese.7z -o./charsChinese -pGBK # 第二步编译需JDK 11 javac -cp .:lib/opencv-455.jar src/main/java/*.java # 第三步运行注意lib路径分隔符为: java -cp .:lib/opencv-455.jar PlateRecogniseController避坑 / 常见问题 / 排查 / 注意现象run.bat双击闪退。原因Windows未安装JDK或JAVA_HOME未指向JDK非JRE。解决命令行输入java -version若显示“java version11.0.20”则正常否则下载Adoptium JDK 11并配置环境变量。现象Mac上java -cp报错“NoClassDefFoundError: org/opencv/core/Core”。原因lib/opencv-455.jar路径错误或lib文件夹内缺少libopencv_java455.dylib。解决从OpenCV官网下载macOS版4.5.5解压后将build/lib/libopencv_java455.dylib复制到项目lib/目录。现象Linux上Imgproc.cvtColor()抛出UnsatisfiedLinkError。原因缺少OpenCV native库的.so文件或LD_LIBRARY_PATH未包含lib/路径。解决执行export LD_LIBRARY_PATH$LD_LIBRARY_PATH:$(pwd)/lib再运行java命令。现象Result.html显示本文还有配套的精品资源点击获取