一个基于OCV的人肉选取特征点程序

基于OpenCV写了一个交互式获取图片上的人肉选取的特征,并保存到文件的小程序。

典型应用场景:当在一个精度不高的应用需求中,相机分辨率差或者变形严重,某些棋盘点通过代码检测不出,就可以通过手工选取的方式。

使用

  • 通过界面的trackbar来缩放图片
  • 单击右键设置显示中心点
  • 单击左键选取并记录点
  • ‘c‘来取消上一次取点
  • ‘q‘退出并保存数据

界面

代码

#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdlib.h>

/*
use guide:
1):left button click to pick one point;
2):right button click to set as the center to display;
3):key ‘c‘ to remove the last picked point
4):key ‘q‘ to quit the program and save point
5):use the "default size scale" to adjust the display size
*/

using namespace cv;
using namespace std;

const bool using_fix_param = true;

const string WIN_NAME = "Pick_Point";
const string SCALE = "scale";
int scale;              //trackbar的值

string data_save_path;  //数据保存路径
string PIC_PATH;        //图片路径
Mat srcImg;             //原始图片
Mat curImg;             //当前显示的图片
Size srcImgSize;        //原始图片大小
Size winSize;           //显示窗口大小
float curScale;         //当前的缩放比例
Point2i curShowCenter;  //当前显示的图像相对于srcImg偏移的坐标
Point2i showRange;      //显示的图片范围,与curShowCenter共同组成了图片的显示范围
int maxScale;           //缩放的最大比例
int minScale;           //缩放的最小比例

vector<Point2f> choosePoints;   //通过本程序选取的点

void showdata() {
    if (false) {
        cout << ">>>>>>>>>>>>>>>>>>>>>>>>\n";
        cout << "curScale:" << curScale << endl;
        cout << "curShowCenter:" << curShowCenter.x << "*" << curShowCenter.y << endl;
        cout << "showRange:" << showRange.x << "*" << showRange.y << endl;
        cout << "winSize:" << winSize.width << "*" << winSize.height << endl;
        cout << "<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n";
    }
}

//define the save-format for yourself during this function
void saveAndQuit(vector<Point2f> pts) {
    const int POINT_PER_LINE = 4;

    FILE *stream = fopen(data_save_path.c_str(), "w");
    for (int i = 0; i < pts.size(); )
    {
        stringstream ss;
        for (int j = 0; j < POINT_PER_LINE && i < pts.size(); ++j, ++i)
        {
            //ss << pts[j].x << ", " << pts[j].y << ", ";
            ss << "Point2f(" << pts[i].x << ", " << pts[i].y << "), ";
        }
        ss << "\n";
        string msg = ss.str();
        if (i == pts.size()) {
            msg = msg.substr(0, msg.length() - 3);
        }
        fwrite(msg.c_str(), msg.length(), 1, stream);
        cout << msg << endl;
    }
    fflush(stream);
    fclose(stream);
}

void keepCenterValid() {
    int minCenterX = winSize.width / curScale / 2;
    int minCenterY = winSize.height / curScale / 2;
    int maxCenterX = srcImgSize.width - minCenterX;
    int maxCenterY = srcImgSize.height - minCenterY;

    if (curShowCenter.x < minCenterX) curShowCenter.x = minCenterX;
    if (curShowCenter.x > maxCenterX) curShowCenter.x = maxCenterX;
    if (curShowCenter.y < minCenterY) curShowCenter.y = minCenterY;
    if (curShowCenter.y > maxCenterY) curShowCenter.y = maxCenterY;
}

void showimg() {
    showdata();

    Mat pts = srcImg.clone();
    drawChessboardCorners(pts, Size(11, 11), choosePoints, false);    //size可以随便写,只要后面为false即可

    int left = curShowCenter.x - showRange.x / 2;
    if (left < 0) left = 0;
    int right = curShowCenter.x + showRange.x / 2;
    if (right > pts.cols) right = pts.cols;
    int top = curShowCenter.y - showRange.y / 2;
    if (top < 0) top = 0;
    int bottom = curShowCenter.y + showRange.y / 2;
    if (bottom > pts.rows) bottom = pts.rows;
    curImg = pts.colRange(left, right).rowRange(top, bottom).clone();

    //cout << curImg.cols << " " << showRange.x << " " << curImg.rows << " " << showRange.y << endl;

    Mat scale_img;
    resize(curImg, scale_img, winSize);

    imshow(WIN_NAME, scale_img);

    void removeLastPoint();
    int key = waitKey();
    if (key == ‘c‘) {
        removeLastPoint();
    }
    else if(key == ‘q‘){
        saveAndQuit(choosePoints);
        cout << "save and quit\n";
        exit(0);
    }
}

void on_scale(int value, void *data) {
    showdata();

    if (scale > maxScale) {
        scale = maxScale;
    }
    if (scale < minScale) {
        scale = minScale;
    }
    curScale = scale / 10.0;

    showRange.x = winSize.width / curScale;
    showRange.y = winSize.height / curScale;

    showimg();
}

void addPoint(int x, int y) {
    //使用这个可以保证计算精度,直接使用curScale可能由于前面计算的取整问题而导致精度问题,对于原图尺寸较大且放大倍数也大时,这个问题会变的比较明显
    const float scaleX = winSize.width / (float)curImg.cols;
    const float scaley = winSize.height / (float)curImg.rows;
    //cout << "add point scale "  << curImg.cols << " " << scaleX << " " << scaley << " " << curScale << endl;
    //使用这种方式,(curShowCenter.x - showRange.x / 2),可以保持和imshow的时候一致,避免出现精度问题
    float picx = (curShowCenter.x - showRange.x / 2) + x / scaleX;
    float picy = (curShowCenter.y - showRange.y / 2) + y / scaley;
    choosePoints.push_back(Point2f(picx, picy));
    cout << ">>>>add:" << picx << " " << picy << endl;
    showimg();
}

void removeLastPoint() {
    if (choosePoints.size() > 0) {
        choosePoints.erase(choosePoints.end() - 1);
        cout << "remove\n";
        showimg();
    }
}

void setShowCenter(int x, int y) {

    curShowCenter.x += (x - winSize.width / 2) / curScale;
    curShowCenter.y += (y - winSize.height / 2) / curScale;

    keepCenterValid();
    showimg();
}

void on_mouse(int event, int x, int y, int flags, void* userdata) {
    switch (event)
    {
    case CV_EVENT_RBUTTONDOWN:  //右键,设定显示中心
        setShowCenter(x, y);
        break;
    case CV_EVENT_LBUTTONDOWN:  //左键单击,选取点
        addPoint(x, y);
        break;
    default:
        break;
    }
}

int main() {

    if (using_fix_param) {
        curScale = 0.3;
    }
    else {
        cout << "please input the default size scale:";
        cin >> curScale;
    }

    if (curScale < 0.1) curScale = 0.1;
    if (curScale > 10) curScale = 10;
    scale = (int)(curScale * 10);
    curScale = scale / 10.0;    //trackbar的值除以10即为缩放比例
    maxScale = 100;
    minScale = scale;

    if (using_fix_param)
    {
        PIC_PATH = "E:\\project\\Car360\\Car360\\HomoToG\\undistort_head.jpg";
    }
    else {
        cout << "\npicture path:";
        cin >> PIC_PATH;
    }

    if (using_fix_param)
    {
        data_save_path = "data.txt";
    }
    else
    {
        cout << "\ndata save path:";
        cin >> data_save_path;
    }

    srcImg = imread(PIC_PATH, 1);
    srcImgSize = srcImg.size();
    curShowCenter = srcImgSize / 2;

    winSize = Size(srcImgSize.width  * curScale, srcImgSize.height * curScale);
    showRange.x = winSize.width / curScale;
    showRange.y = winSize.height / curScale;

    namedWindow(WIN_NAME);
    createTrackbar(SCALE, WIN_NAME, &scale, 100, on_scale);
    setMouseCallback(WIN_NAME, on_mouse);

    showimg();

    waitKey();
    return 0;
}

原文地址:https://www.cnblogs.com/willhua/p/10225937.html

时间: 2024-10-07 21:03:46

一个基于OCV的人肉选取特征点程序的相关文章

Xamarin 小试牛刀 通知栏消息通知和按钮(基于Java代码人肉转换)

本示例基于网友现有安卓项目人肉翻译,在Xamarin中替换和修改了很多方法的命名,比如某些属性需要去掉getName的get前缀, 有些方法名称需要使用Pascal命名法替换Java的Camel 命名规范 另外在内部类的使用方式上也有一些区别,但是整体上来说,大部分的方法名称都与Java 原版Android一致,所以如果有现有的Android 项目需要转换到Xamarin 还是很容易的.此处给Xamarin 66个赞 参考Java版本:http://blog.csdn.net/wxdjaqgs/

yunBT:一个基于TP3.1的多用户BT离线下载程序,支持在线播放

说明:yunBT这个项目其实很早就有了,只是老没更新,现在作者基于ThinkCMS重做该程序,支持多用户注册下载,Magnet和HTTP下载.每个单独用户支持10个任务,默认下载文件最大为10GB,可以在后台修改.下载完成后用户可以直接查看下载的文件仅支持mp4文件在线播放.管理员可以添加用户的下载量及查看管理下载任务. 由于该程序刚出来,功能较少,暂不支持下载工具下载,可以在浏览器中下载,后续将添加,而且作者计划以后会增加分享功能.用户转码功能.积分功能.邀请功能.工具下载.使用Onedriv

人肉刷页面时ECS服务器的压力快照

系统概况:阿里云ECS,1G内存,单核,带宽1Mbps. [[email protected] quickdist]# free total used free shared buffers cached Mem: 1020648 917988 102660 0 187980 238204 -/+ buffers/cache: 491804 528844 Swap: 0 0 0 [[email protected] quickdist]# cat /proc/c cgroups cmdline

eShopOnContainers 是一个基于微服务的.NET Core示例框架

找到一个好的示例框架很难,但不是不可能.大多数是小型Todo风格的应用程序,通常基于SimpleCRUD.值得庆幸的是,Microsoft已经为eShopOnContainers创建了一个基于微服务的.NET Core示例应用程序. eShopOnContainers是 .NET Core示例应用框架,由Microsoft提供支持,基于简化的微服务架构和Docker容器技术. 这个示例应用程序在服务器和客户端是跨平台的,这要归功于.NET Core服务能够在Linux或Windows容器上运行,

人肉工程在机器学习实践中的作用

关于人肉工程,包括业务知识.领域知识,经验等,在实际的机器学习问题中的应用,是一个屡见不鲜的话题,典型的有苦逼的数据清洗.人肉特征工程等.大家都想把尽可能多的过程由机器自动完成,但是目前的状态是,大部分机器学习问题中,最困难也最重要的部分,还是依靠人的经验来生成特征.那么人的经验为什么重要,能否用机器完成这个过程,本文试作一简单分析. 机器和人看待数据的区别 首先要看一下,从机器的角度看,机器学习是怎样一个问题?在机器看来,机器学习的问题通常是在一组特征上,最大化某个目标函数.注意,对于这组特征

基于视觉的人的运动识别综述

人的运动识别 ,可以简单地看成一个时变数据的分类问题 ,包括运动的表示和运动的识别两部分 人运动的类别 人的运动可以分为三类 : 动作 ( movement ) .行为 ( activity) 和行动 ( action) , 这三类运动分别处于三个不同复杂程度的层次上. 动作是运动的基元 ,是最基本的运动 , 是形成其他复杂 . 高级运动的基础. 一般来说动作在执行过程中会持续较短的时间 ,其识别方法一般可以采用几何或概率统计的方法. 譬如 ,打网球时挥动了一下球拍 ,这就是一个动作. 行为是指

逃离北上广之后,老码农的悲哀(顺便晒下简历,请围观,但请勿人肉,求放过!求无视!)

在此记录一下,逃离北上广之后的五个月后的今日的感想. 前戏: 最近老板出去旅游了,要十几天才回来.由于老婆最近总是在碎碎念,说小孩在成都读不起书,收入降低了这么多,真是不该回来!云云... 顺便说一下现状吧,本来是受朋友邀请才回来工作的,也就是现在的BOSS,我的王哥,王哥对我还是挺照顾的,也是非常的感谢.公司是做传统收银管理软件的,在现在的行业内一直是国内领先,效益还算可以,加上王哥自己开发有4个人,但是主力开发由于身体原因已经在家修养了半年多了,一直没来上班.由于软件是delphi开发的,面

论王宝强事件黑客教你人肉搜索的七种方法

作为敢抢奥运会头条的男人,宋喆遭遇了围追堵截.这次全民捉奸不仅是娱乐圈的狂欢,科技圈也神乱入了一下: 如果没有广大黑客技术爱好者的参与,狗仔们似乎也无法在几天之内扒出宋喆的身世.爱好.住址.开房记录,用体无完肤来形容毫不为过. [网友总结的宋喆个人信息(保护公民隐私,敏感信息已被打码)] 实际上,黑客们认真捉起奸来,可以获得诸多让人惊讶掉下巴的奇异信息.雷锋网决定向顶级黑客请教一下,暂时抛开法律和道德因素,究竟怎样人肉一个人呢?或者从反面来说,如果你不小心爱上了明星的媳妇而成为了全民公敌,如何避

简述人脸特异性识别&amp;&amp;一个基于LBP和SVM的人脸识别小例子

原谅我用图片,MAC在Safari里给文章进行图文排版太麻烦啦~ 本文适合初入计算机视觉和模式识别方向的同学们观看~ 文章写得匆忙,加上博主所知甚少,有不妥和勘误请指出并多多包涵. 本文Demo的代码由HZK编写,特征点由月神和YK选择和训练. 转载请注明 copyleft by sciencefans, 2014 为了方便大家学习,附上高维LBP的核心代码 1 ################################################### 2 # 3 # 4 # NO