Opencv创建车牌图片识别系统方法详解

目录
  • 前言
    • 包含功能
    • 软件版本
    • 软件架构
    • 参考文档
  • 效果图展示
  • 车牌检测过程
  • 图片车牌文字识别过程
  • 部分核心代码

前言

这是一个基于spring boot + maven + opencv 实现的图像识别及训练的Demo项目

包含车牌识别、人脸识别等功能,贯穿样本处理、模型训练、图像处理、对象检测、对象识别等技术点

java语言的深度学习项目,在整个开源社区来说都相对较少;

拥有完整的训练过程、检测、识别过程的开源项目更是少之又少!!

包含功能

  • 蓝、绿、黄车牌检测及车牌号码识别
  • 网上常见的轮廓提取车牌算法JAVA实现
  • hsv色彩分割提取车牌算法JAVA实现
  • 基于svm算法的车牌检测训练JAVA实现
  • 基于ann算法的车牌号码识别训练JAVA实现
  • 人脸检测 接下来将实现人脸识别
  • 图片处理工具,目前实现了HSV色彩切割,后续将添加更多使用的图片处理工具,用于辅助算法优化

软件版本

  • jdk 1.8.61+
  • maven 3.0+
  • opencv 4.0.1 ; javacpp1.4.4;opencv-platform 4.0.1-1.4.4
  • spring boot 2.1.5.RELEASE
  • yx-image-recognition 1.0.0版本

软件架构

B/S 架构,前端html + requireJS,后端java

数据库使用 sqlite3.0

接口文档使用swagger 2.0

参考文档

参考了EasyPR C++项目、以及fan-wenjie的EasyPR-Java项目;同时查阅了部分opencv官方4.0.1版本C++的源码,结合个人对java语言的理解,整理出当前项目

liuruoze/EasyPR

fan-wenjie/EasyPR-Java

opencv官方

效果图展示

车牌识别

黄牌识别

绿牌识别

夜间识别

图片提取工具

人脸识别

训练

接口文档

车牌检测过程

高斯模糊:

图像灰度化:

Sobel 算子:

图像二值化:

图像闭操作:

二值图像降噪:

提取外部轮廓:

外部轮廓筛选:

切图:

重置切图尺寸:

车牌检测结果:

图片车牌文字识别过程

车牌检测结果:

debug_char_threshold:

debug_char_clearLiuDing:

debug_specMat:

debug_chineseMat:

debug_char_auxRoi:

部分核心代码

package com.yuxue.service.impl;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.yuxue.constant.Constant;
import com.yuxue.entity.PlateFileEntity;
import com.yuxue.entity.TempPlateFileEntity;
import com.yuxue.enumtype.PlateColor;
import com.yuxue.mapper.PlateFileMapper;
import com.yuxue.mapper.TempPlateFileMapper;
import com.yuxue.service.PlateService;
import com.yuxue.util.FileUtil;
import com.yuxue.util.GenerateIdUtil;
import com.yuxue.util.PlateUtil;

@Service
public class PlateServiceImpl implements PlateService {

    @Autowired
    private PlateFileMapper plateFileMapper;

    @Autowired
    private TempPlateFileMapper tempPlateFileMapper;

    static {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Object refreshFileInfo() {
        File baseDir = new File(Constant.DEFAULT_DIR);
        if(!baseDir.exists() || !baseDir.isDirectory()) {
            return null;
        }
        List<TempPlateFileEntity> resultList = Lists.newArrayList();

        // 获取baseDir下第一层级的目录, 仅获取文件夹,不递归子目录,遍历
        List<File> folderList = FileUtil.listFile(baseDir, ";", false);
        folderList.parallelStream().forEach(folder -> {
            if(!folder.getName().equals("temp")) {
                // 遍历每一个文件夹, 递归获取文件夹下的图片
                List<File> imgList = FileUtil.listFile(folder, Constant.DEFAULT_TYPE, true);
                if(null != imgList && imgList.size() > 0) {
                    imgList.parallelStream().forEach(n->{
                        TempPlateFileEntity entity = new TempPlateFileEntity();
                        entity.setFilePath(n.getAbsolutePath().replaceAll("\\\\", "/"));
                        entity.setFileName(n.getName());
                        entity.setFileType(n.getName().substring(n.getName().lastIndexOf(".") + 1));
                        resultList.add(entity);
                    });
                }
            }
        });

        tempPlateFileMapper.turncateTable();
        tempPlateFileMapper.batchInsert(resultList);
        tempPlateFileMapper.updateFileInfo();
        return 1;
    }

    @Override
    public Object recognise(String filePath, boolean reRecognise) {
        filePath = filePath.replaceAll("\\\\", "/");
        File f = new File(filePath);
        PlateFileEntity entity = null;

        Map<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("filePath", filePath);
        List<PlateFileEntity> list= plateFileMapper.selectByCondition(paramMap);
        if(null == list || list.size() <= 0) {
            if(FileUtil.checkFile(f)) {
                entity = new PlateFileEntity();
                entity.setFileName(f.getName());
                entity.setFilePath(f.getAbsolutePath().replaceAll("\\\\", "/"));
                entity.setFileType(f.getName().substring(f.getName().lastIndexOf(".") + 1));
                plateFileMapper.insertSelective(entity);
            }
            reRecognise = true;
        } else {
            entity = list.get(0);
        }

        if(reRecognise || StringUtils.isEmpty(entity.getTempPath())) {
            doRecognise(f, entity); // 重新识别
            entity = plateFileMapper.selectByPrimaryKey(entity.getId()); // 重新识别之后,重新获取一下数据
        }
        // 查询debug文件
        if(!StringUtils.isEmpty(entity.getTempPath())) {
            Vector<String> debugFiles = new Vector<String>();
            FileUtil.getFiles(entity.getTempPath(), debugFiles);
            entity.setDebugFiles(debugFiles);
        }
        return entity;
    }

    @Override
    public Object recogniseAll() {
        // 查询到还没有进行车牌识别的图片
        List<PlateFileEntity> list = plateFileMapper.getUnRecogniseList();
        list.parallelStream().forEach(n->{
            File f = new File(n.getFilePath());
            if(FileUtil.checkFile(f)) {
                doRecognise(f, n);
            }
        });
        return 1;
    }

    /**
     * 单张图片 车牌识别
     * 拷贝文件到临时目录
     * 过程及结果更新数据库
     * @param f
     * @param e
     * @return
     */
    public Object doRecognise(File f, PlateFileEntity e) {
        if(!f.exists()) {
            return null;
        }

        String ct = GenerateIdUtil.getStrId();
        String targetPath = Constant.DEFAULT_TEMP_DIR + ct + (f.getName().substring(f.getName().lastIndexOf(".")));
        FileUtil.copyAndRename(f.getAbsolutePath(), targetPath); // 拷贝文件并且重命名

        // 创建临时目录, 存放过程图片
        String tempPath =  Constant.DEFAULT_TEMP_DIR + ct + "/";
        FileUtil.createDir(tempPath);
        e.setTempPath(tempPath);

        Boolean debug = false;
        Vector<Mat> dst = new Vector<Mat>();
        PlateUtil.getPlateMat(targetPath, dst, debug, tempPath);

        Set<String> plates = Sets.newHashSet();
        dst.stream().forEach(inMat -> {
            PlateColor color = PlateUtil.getPlateColor(inMat, true, false, tempPath);
            String plate = PlateUtil.charsSegment(inMat, color, debug, tempPath);
            plates.add("<" + plate + "," + color.desc + ">");
        });
        e.setRecoPlate(plates.toString());

        new File(targetPath).delete();  // 删除拷贝的临时文件
        plateFileMapper.updateByPrimaryKeySelective(e);
        return 1;
    }

    @Override
    public Object getImgInfo(String imgPath) {
        Map<String, Object> result = Maps.newHashMap();
        String ct = GenerateIdUtil.getStrId();
        File f = new File(imgPath);
        if(f.exists()) {
            String targetPath = Constant.DEFAULT_TEMP_DIR + ct + (f.getName().substring(f.getName().lastIndexOf(".")));
            FileUtil.copyAndRename(f.getAbsolutePath(), targetPath);
            result.put("targetPath", targetPath);   // 返回临时路径给前端
            // 获取图片的基本信息
            Mat inMat = Imgcodecs.imread(targetPath);
            result.put("rows", inMat.rows());
            result.put("cols", inMat.cols());
        }
        return result;
    }

    @Override
    public Object getHSVValue(String imgPath, Integer row, Integer col) {
        Map<String, Object> result = Maps.newHashMap();
        Mat inMat = Imgcodecs.imread(imgPath);

        double[] rgb = inMat.get(row, col);
        result.put("RGB", JSONObject.toJSONString(rgb));

        Mat dst = new Mat(inMat.rows(), inMat.cols(), CvType.CV_32FC3);
        Imgproc.cvtColor(inMat, dst, Imgproc.COLOR_BGR2HSV); // 转到HSV空间进行处理

        double[] hsv = dst.get(row, col);
        result.put("HSV", (int)hsv[0] + ", " + (int)hsv[1] + ", " + (int)hsv[2]);
        return result;
    }

}
package com.znz.service.impl;

import com.znz.service.PlateTypeService;
import com.znz.entity.PlateTypeEntity;
import com.znz.mapper.PlateTypeMapper;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Propagation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.List;

/**
 * 服务实现层
 * @author znz
 * @date 2020-09-30T16:54:41.823
 */
@Service
public class PlateTypeServiceImpl implements PlateTypeService {

    @Autowired
    private PlateTypeMapper plateTypeMapper;

    @Override
    public PlateTypeEntity getByPrimaryKey(Integer id) {
        PlateTypeEntity entity = plateTypeMapper.selectByPrimaryKey(id);
        return entity;
    }

    @Override
    public PageInfo<PlateTypeEntity> queryByPage(Integer pageNo, Integer pageSize, Map<String, Object> map) {
    	PageHelper.startPage(pageNo, pageSize);
		PageInfo<PlateTypeEntity> page = new PageInfo(plateTypeMapper.selectByCondition(map));
		return page;
    }

    @Override
    public List<PlateTypeEntity> queryByCondition(Map<String, Object> map) {
		return plateTypeMapper.selectByCondition(map);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Map<String, Object> save(PlateTypeEntity plateTypeEntity) {
    	plateTypeEntity.setId(0);
    	plateTypeMapper.insertSelective(plateTypeEntity);

    	Map<String, Object> result = new HashMap<>();
    	result.put("id" , plateTypeEntity.getId());
    	return result;
    }

    @Override
	@Transactional(propagation = Propagation.REQUIRED)
	public Integer deleteById(Integer id){
		return plateTypeMapper.deleteByPrimaryKey(id);
	}

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Integer updateById(PlateTypeEntity plateTypeEntity) {
    	if(null == plateTypeEntity || plateTypeEntity.getId() <= 0){
    		return 0;
    	}
    	return plateTypeMapper.updateByPrimaryKeySelective(plateTypeEntity);
    }

}
package com.znz.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.znz.entity.SystemMenuEntity;
import com.znz.mapper.SystemMenuMapper;
import com.znz.service.SystemMenuService;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Propagation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 服务实现层
 * @author znz
 * @date 2021-06-20 16:15:23
 */
@Service
public class SystemMenuServiceImpl  implements SystemMenuService {

    @Autowired
    private SystemMenuMapper systemMenuMapper;

    @Override
    public SystemMenuEntity getByPrimaryKey(Integer id) {
        SystemMenuEntity entity = systemMenuMapper.selectByPrimaryKey(id);
        return entity;
    }

    @Override
    public PageInfo<SystemMenuEntity> queryByPage(Integer pageNo, Integer pageSize, Map<String, Object> map) {
    	PageHelper.startPage(pageNo, pageSize);
		PageInfo<SystemMenuEntity> page = new PageInfo(systemMenuMapper.selectByCondition(map));
		return page;
    }

    @Override
	public List<SystemMenuEntity> queryByCondition(Map<String, Object> map) {
		return systemMenuMapper.selectByCondition(map);
	}

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Map<String, Object> save(SystemMenuEntity entity) {
    	entity.setId(0);
    	systemMenuMapper.insertSelective(entity);

    	Map<String, Object> result = new HashMap<>();
    	result.put("id" , entity.getId());
    	return result;
    }

	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public Integer deleteById(Integer id){
		return systemMenuMapper.deleteByPrimaryKey(id);
	}

	@Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Integer updateById(SystemMenuEntity systemMenuEntity) {
    	if(null == systemMenuEntity || systemMenuEntity.getId() <= 0){
    		return 0;
    	}
    	return systemMenuMapper.updateByPrimaryKeySelective(systemMenuEntity);
    }

	@Override
    public Object getUserMenu() {
        Map<String, Object> map = Maps.newHashMap();
        map.put("showFlag", 1);
        List<SystemMenuEntity> menus = systemMenuMapper.selectByCondition(map);

        //按层级封装,最多三级
        Map<String, Object> result = Maps.newHashMap();

        result.put("first", menus.stream().filter(n -> {
            return n.getMenuLevel() == 1;
        }));
        result.put("second", menus.stream().filter(n -> {
            return n.getMenuLevel() == 2;
        }));
        result.put("third", menus.stream().filter(n -> {
            return n.getMenuLevel() == 3;
        }));
        return result;
    }

}
package com.znz.service.impl;

import java.io.File;
import java.util.List;

import org.springframework.stereotype.Service;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.znz.constant.Constant;
import com.znz.exception.ResultReturnException;
import com.znz.service.FileService;
import com.znz.util.FileUtil;

@Service
public class FileServiceImpl implements FileService {

    @Override
    public List<JSONObject> getFileTreeByDir(String rootPath, String dir, String typeFilter) {

        if(StringUtils.isEmpty(dir)){
            if(StringUtils.isEmpty(rootPath)){
                dir = Constant.DEFAULT_DIR;
            } else {
                dir = rootPath;
            }
        }
        if(StringUtils.isEmpty(typeFilter)){
            typeFilter = Constant.DEFAULT_TYPE;
        }

        File f = new File(dir);
        List<File> list = FileUtil.listFile(f, typeFilter, false);
        List<JSONObject> result = Lists.newArrayList();
        list.stream().forEach(n->{
            JSONObject jo = new JSONObject();
            jo.put("id", n.getAbsolutePath());
            jo.put("pid", n.getParentFile().getAbsolutePath());
            jo.put("filePath", n.getAbsolutePath());
            jo.put("fileName", n.getName());
            jo.put("isDir", n.isDirectory());
            result.add(jo);
        });
        return result;
    }

    @Override
    public File readFile(String filePath) {

        File f = new File(filePath);
        if(!f.exists() || f.isDirectory()) {
            throw new ResultReturnException("filePath参数异常,找不到指定的文件: " + filePath);
        }

        if(!f.exists() || f.isDirectory()) {
            throw new ResultReturnException("读取图片异常:" + f.getName());
        }
        return f;
    }

}

以上就是Opencv创建车牌图片识别系统方法详解的详细内容,更多关于Opencv车牌图片识别系统的资料请关注我们其它相关文章!

(0)

相关推荐

  • OpenCV+Python识别车牌和字符分割的实现

    本篇文章主要基于python语言和OpenCV库(cv2)进行车牌区域识别和字符分割,开篇之前针对在python中安装opencv的环境这里不做介绍,可以自行安装配置! 车牌号检测需要大致分为四个部分: 1.车辆图像获取 2.车牌定位. 3.车牌字符分割 4.车牌字符识别 具体介绍 车牌定位需要用到的是图片二值化为黑白后进canny边缘检测后多次进行开运算与闭运算用于消除小块的区域,保留大块的区域,后用cv2.rectangle选取矩形框,从而定位车牌位置 车牌字符的分割前需要准备的是只保留车牌

  • Python+OpenCV实现车牌字符分割和识别

    最近做一个车牌识别项目,入门级别的,十分简单. 车牌识别总体分成两个大的步骤: 一.车牌定位:从照片中圈出车牌 二.车牌字符识别 这里只说第二个步骤,字符识别包括两个步骤: 1.图像处理 原本的图像每个像素点都是RGB定义的,或者称为有R/G/B三个通道.在这种情况下,很难区分谁是背景,谁是字符,所以需要对图像进行一些处理,把每个RGB定义的像素点都转化成一个bit位(即0-1代码),具体方法如下: ①将图片灰度化 名字拗口,但是意思很好理解,就是把每个像素的RGB都变成灰色的RGB值,而灰色的

  • python+OpenCV实现车牌号码识别

    基于python+OpenCV的车牌号码识别,供大家参考,具体内容如下 车牌识别行业已具备一定的市场规模,在电子警察.公路卡口.停车场.商业管理.汽修服务等领域已取得了部分应用.一个典型的车辆牌照识别系统一般包括以下4个部分:车辆图像获取.车牌定位.车牌字符分割和车牌字符识别 1.车牌定位的主要工作是从获取的车辆图像中找到汽车牌照所在位置,并把车牌从该区域中准确地分割出来 这里所采用的是利用车牌的颜色(黄色.蓝色.绿色) 来进行定位 #定位车牌 def color_position(img,ou

  • Java通过百度API实现图片车牌号识别

    本代码功能是通过调用百度API实现的,所有你需要去百度API官网申请下你的API Key 以及Secret Key才能使用它的功能哦! 拟采用百度AI实现该功能(http://ai.baidu.com/docs#/OCR-API/5116ac95) 根据百度的文档描述,初步明确需要的几个参数为: 1.应用的API Key 2.应用的Secret Key 3.access_token 4.图片数据 首先导入maven依赖 <dependency> <groupId>com.baidu

  • Opencv创建车牌图片识别系统方法详解

    目录 前言 包含功能 软件版本 软件架构 参考文档 效果图展示 车牌检测过程 图片车牌文字识别过程 部分核心代码 前言 这是一个基于spring boot + maven + opencv 实现的图像识别及训练的Demo项目 包含车牌识别.人脸识别等功能,贯穿样本处理.模型训练.图像处理.对象检测.对象识别等技术点 java语言的深度学习项目,在整个开源社区来说都相对较少: 拥有完整的训练过程.检测.识别过程的开源项目更是少之又少!! 包含功能 蓝.绿.黄车牌检测及车牌号码识别 网上常见的轮廓提

  • OpenCV Python身份证信息识别过程详解

    目录 前置环境 识别过程 身份证区域查找 原始图像 灰度处理 中值滤波 二值处理 边缘检测 边缘膨胀 轮廓检测 轮廓排序 透视变换 固定图像大小 检测身份证文本位置 极度膨胀 轮廓查找文本区域 筛选出文本区域 对文本区域进行排序 识别文本 结语 代码 本篇文章使用OpenCV-Python和CnOcr来实现身份证信息识别的案例.想要识别身份证中的文本信息,总共分为三大步骤:一.通过预处理身份证区域检测查找:二.身份证文本信息提取:三.身份证文本信息识别.下面来看一下识别的具体过程CnOcr官网.

  • Android图片识别应用详解

    最近由于参加一个小小的创意比赛,用安卓做了一个小小的图片识别应用,主要是通过拍照识别图片中的菜品,还有对象位置查找的东西.之前没有做过安卓,都是拼拼凑凑多篇博客完成的,我也把这个项目的一些过程分享一下.先把功能贴一下,其实就是点击拍照,将照片保存在本地,然后识别出图中的菜品,然后用红色方框圈出来,并显示菜品种类.采用最新的Camera2的API,的确是比Camera好用. 1.界面 我采用了一个SurfaceView用来显示摄像头的预览画面,重写了一个SurfaceView来进行红色方框还有菜品

  • python计算机视觉opencv卡号识别示例详解

    目录 一.模板预处理 1.将模板设置为二值图 2.检测模板的轮廓 3.对模板轮廓排序,并将数字和轮廓一一对应,以字典存储 4.备注 二.图片预处理 1.初始化卷积核 2.图片预处理第一部分 3.图像预处理第二部分 三.轮廓处理 1.大轮廓过滤 2.小轮廓分割 模板图片如下: 需识别的图片如下: 一.模板预处理 1.将模板设置为二值图 2.检测模板的轮廓 3.对模板轮廓排序,并将数字和轮廓一一对应,以字典存储 排序的函数如下: 排序并存储: 4.备注 ①每一个数字对应的是二值图截出来的那个数字图的

  • 基于Opencv图像识别实现答题卡识别示例详解

    目录 1. 项目分析 2.项目实验 3.项目结果 总结 在观看唐宇迪老师图像处理的课程中,其中有一个答题卡识别的小项目,在此结合自己理解做一个简单的总结. 1. 项目分析 首先在拿到项目时候,分析项目目的是什么,要达到什么样的目标,有哪些需要注意的事项,同时构思实验的大体流程. 图1. 答题卡测试图像 比如在答题卡识别的项目中,针对测试图片如图1 ,首先应当实现的功能是: 能够捕获答题卡中的每个填涂选项. 将获取的填涂选项与正确选项做对比计算其答题正确率. 2.项目实验 在对测试图像进行形态学操

  • Python中操作各种多媒体,视频、音频到图片的代码详解

    我们经常会遇到一些对于多媒体文件修改的操作,像是对视频文件的操作:视频剪辑.字幕编辑.分离音频.视频音频混流等.又比如对音频文件的操作:音频剪辑,音频格式转换.再比如我们最常用的图片文件,格式转换.各个属性的编辑等.因为多媒体文件的操作众多,本文选取一些极具代表性的操作,以代码的形式实现各个操作. 一.图片操作 操作图片的模块有许多,其中比较常用的两个就是 Pillow 和 opencv ,两个模块各有优势.其中 opencv 是计算机视觉处理的开源模块,应用的范围更加广泛,从图像处理到视频处理

  • Unity实现植物识别示例详解

    接口介绍: 可识别超过2万种常见植物和近8千种花卉,接口返回植物的名称,并支持获取识别结果对应的百科信息:还可使用EasyDL定制训练平台,定制识别植物种类.适用于拍照识图.幼教科普.图像内容分析等场景. 创建应用: 在产品服务中搜索图像识别,创建应用,获取AppID.APIKey.SecretKey信息: 查阅官方文档,以下是植物识别接口返回数据参数详情: 定义数据结构: using System; /// <summary> /// 植物识别 /// </summary> [S

  • Python+OpenCV实现阈值分割的方法详解

    目录 一.全局阈值 1.效果图 2.源码 二.滑动改变阈值(滑动条) 1.效果图 2.源码 三.自适应阈值分割 1.效果图 2.源码 3.GaussianBlur()函数去噪 四.参数解释 一.全局阈值 原图: 整幅图采用一个阈值,与图片的每一个像素灰度进行比较,重新赋值: 1.效果图 2.源码 import cv2 import matplotlib.pyplot as plt #设定阈值 thresh=130 #载入原图,并转化为灰度图像 img_original=cv2.imread(r'

  • C# OpenCV实现形状匹配的方法详解

    1. 多角度模板匹配测试效果如下图: 图1-1 图1-2 图1-3 正负角度均可正常识别,识别角度偏差<1° 2. 下面分享一下开发过程: a). ROI区域的生成,基于GDI+完成图形绘制,如图 绘制模板设置区域,用来生成需要的模板特征. ROI区域绘制代码如下: /// <summary> /// 区域绘制 /// </summary> /// <param name="graphics"></param> /// <pa

  • IOS 调整内存中的图片大小实例详解

    IOS 调整内存中的图片大小实例详解 在从网路download图片,或者从相册读取图片的时候,如果ImageView的本身就是固定的300*200,那么载入2000*2000的图片是很浪费内存的. 2000*2000的内存占用是2000*2000*4bit 以下两个函数可以用来创建一个新的按照固定大小的图片.简单来说,就是Core Graphics来创建一个bitmap,然后生成一个图片. - (UIImage*)imageWithImage:(UIImage*)image scaledToSi

随机推荐