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

opencv提取保存轮廓图

pragma once

include "open2_public.h"

class ld_yjt_sub_image
{
public:

//获取src_mat的轮廓个数,介于nMinSzie和nMaxSize之间的才会放入到evc_contours中
bool                getContours(const Mat& src_mat, vector<vector<Point>>& evc_contours,
                                const int& nMinSzie = 500, const int& nMaxSize = 100000);

//生成影像名称
string                getNewImage();

//提取出子影像文件
bool                extract_sub_image(const string& src_image, vector<string>& vec_sub_image);

private:

//错误信息
CString                m_strErrMsg;

public:

ld_yjt_sub_image();
virtual ~ld_yjt_sub_image();

};

include "stdafx.h"

include "ld_yjt_sub_image.h"

int g_lImageCount = 0;

ld_yjt_sub_image::ld_yjt_sub_image()
{
}

ld_yjt_sub_image::~ld_yjt_sub_image()
{
}

//获取src_mat的轮廓个数,介于nMinSzie和nMaxSize之间的才会放入到evc_contours中
bool ld_yjt_sub_image::getContours(const Mat& src_mat, vector>& evc_contours,

const int& nMinSzie, const int& nMaxSize)

{

if (src_mat.empty())
{
    m_strErrMsg = "原始矩阵为空,无法获取轮廓个数";
    return false;
}

if (src_mat.channels() != 3)
{
    m_strErrMsg.Format("原始矩阵通道个数不为3个");
    return false;
}

Mat mat_clone = src_mat.clone();

//灰度图像
cvtColor(mat_clone, mat_clone, COLOR_BGR2GRAY);

//对图像进行二值化
threshold(mat_clone, mat_clone, 80, 255, THRESH_BINARY);

vector<vector<Point>> evc_temp_contours;

//提取轮廓元素
findContours(mat_clone, evc_temp_contours, CV_RETR_TREE, CHAIN_APPROX_NONE);

for (int i = 0; i < evc_temp_contours.size(); i++)
{
    if (evc_temp_contours[i].size() < nMinSzie ||
        evc_temp_contours[i].size() > nMaxSize)  //轮廓尺寸过小或者过大
        continue;

    //添加进入容器
    evc_contours.push_back(evc_temp_contours[i]);
}
return true;

}

//生成影像名称
string ld_yjt_sub_image::getNewImage()
{

string str_new_image = "new_image";
str_new_image.append(to_string(g_lImageCount++));
str_new_image.append(".jpg");
return str_new_image;

}

//提取出子影像文件
bool ld_yjt_sub_image::extract_sub_image(const string& src_image, vector& vec_sub_image)
{

Mat src_mat = imread(src_image);
if (src_mat.empty())
{
    m_strErrMsg.Format("打开影像文件[%s]失败", src_image.c_str());
    return false;
}
vector<vector<Point>> evc_contours;
if (!getContours(src_mat, evc_contours))
    return false;
for (int i = 0; i < evc_contours.size(); i++)
{
    //获取区域坐标
    Rect rt = boundingRect(evc_contours[i]);

    //获取倾斜角度
    RotatedRect rotate = minAreaRect(evc_contours[i]);

    //如果角度超过5度,就需要做旋转
    float angle = rotate.angle;
    if (abs(angle) > 5)
    {
        cout << "倾斜角度大于5度" << endl;

        //获取矩形的四个坐标点
        Point2f rectpoint[4];
        rotate.points(rectpoint);

        //计算两条边的长度  
        int line1 = sqrt((rectpoint[1].y - rectpoint[0].y)*(rectpoint[1].y - rectpoint[0].y) + (rectpoint[1].x - rectpoint[0].x)*(rectpoint[1].x - rectpoint[0].x));
        int line2 = sqrt((rectpoint[3].y - rectpoint[0].y)*(rectpoint[3].y - rectpoint[0].y) + (rectpoint[3].x - rectpoint[0].x)*(rectpoint[3].x - rectpoint[0].x));
    
        //为了让正方形横着放,所以旋转角度是不一样的  
        if (line1 > line2) //  
            angle = 90 + angle;
        
        //直接克隆一个矩阵
        Mat warp_mat = src_mat(rt).clone();

        //计算绕图像中点顺时针旋转50度缩放因子为0.8的旋转矩阵
        Point center = Point(warp_mat.cols / 2, warp_mat.rows / 2);
        double scale = 1;

        //通过上面的旋转细节信息求得旋转矩阵
        Mat rot_mat = getRotationMatrix2D(center, angle, scale);

        //旋转已扭曲图像
        warpAffine(warp_mat, warp_mat, rot_mat, warp_mat.size());
        //imshow("warp_mat", warp_mat);

        //再次提取轮廓
        vector<vector<Point>> evc_warp_contours;
        if (!getContours(warp_mat, evc_warp_contours))
            return false;
        for (int j = 0; j<evc_warp_contours.size(); j++)
        {
            //获取区域坐标
            Rect warp_rt = boundingRect(evc_warp_contours[j]);
            string ImageName = getNewImage();
            imwrite(ImageName, warp_mat(warp_rt));
            vec_sub_image.push_back(ImageName);
        }

        waitKey(0);
    }
    else
    {
        cout << "倾斜角度小于5度" << endl;
        /// 设置目标图像的大小和类型与源图像一致
        Mat warp_dst = Mat::zeros(src_mat.rows, src_mat.cols, src_mat.type());
        warp_dst.setTo(cv::Scalar(100, 0, 0));
        src_mat(rt).copyTo(warp_dst);
        string str_new_image = getNewImage();
        imwrite(str_new_image, warp_dst);
        vec_sub_image.push_back(str_new_image);
    }

    
}

}

相关文章:

  • Vue中注意target和currentTarget的使用
  • 并发-4-volatile
  • [SDOI2009]Elaxia的路线
  • ES学习笔记(12)--Symbol
  • Redis 中的布隆过滤器
  • json字符串 转换为数组
  • 用mpvue开发微信小程序
  • hadoop副本放置策略
  • 【逆序对】N*M Puzzle / Simple Puzzle
  • JavaCV cvEstimateRigidTransform函数使用心得
  • 10.17_T1 平津战役
  • EOS开发完全解析(二):用cleos命令行创建、导入、解锁钱包
  • 返回一个二维整数数组中最大子数组的和
  • 1、jeecg 笔记开篇
  • 论文笔记:Visual Semantic Navigation Using Scene Priors
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • codis proxy处理流程
  • Create React App 使用
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • java2019面试题北京
  • PHP变量
  • Sublime Text 2/3 绑定Eclipse快捷键
  • uva 10370 Above Average
  • windows下如何用phpstorm同步测试服务器
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 前端自动化解决方案
  • 容器服务kubernetes弹性伸缩高级用法
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • $.proxy和$.extend
  • (分布式缓存)Redis哨兵
  • (十八)devops持续集成开发——使用docker安装部署jenkins流水线服务
  • (万字长文)Spring的核心知识尽揽其中
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)Oracle存储过程编写经验和优化措施
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .NET 依赖注入和配置系统
  • .netcore如何运行环境安装到Linux服务器
  • @Documented注解的作用
  • @RequestMapping处理请求异常
  • @zabbix数据库历史与趋势数据占用优化(mysql存储查询)
  • [Android]如何调试Native memory crash issue
  • [Angular] 笔记 20:NgContent
  • [C#]扩展方法
  • [git]git命令如何取消先前的配置
  • [Hadoop in China 2011] 蒋建平:探秘基于Hadoop的华为共有云
  • [hive] sql中distinct的用法和注意事项
  • [JS真好玩] 掘金创作者必备: 监控每天是谁取关了你?
  • [NOI2020统一省选 A] 组合数问题 (推式子)
  • [Oh My C++ Diary]函数重载
  • [Oh My C++ Diary]内联函数
  • [one_demo_9]判断数组是否递增
  • [PTA]数组循环右移
  • [SDOI 2009]HH去散步