ATP的OpenCV笔记(一):对图片的基本操作

Stella981
• 阅读 625

##写在前面

ATP成功进化成弃坑大师。。

主要是正式开课以后自己乱搞着玩儿的东西就不想管它了QAQ。。。Python学会了以后也懒得往博客里写了。。

这次打算开的坑emmm是上课讲的内容?由于要记住的函数用法太多ATP懒得每次遇到都百度所以相当于在blog里面记一下嗯就是这样。

OpenCV是个可以用来做图像处理的库?在C++和python里面都有对应的版本,不过C++的配置环境好麻烦。。python的还不大会。。而且上课要用的是C++的所以暂且先记一下C++的?

OpenCV具体怎么安装怎么配置什么的。。。ATP因为是直接按照助教老师发的文档照葫芦画瓢自己也不是很明白所以就不写了。。。

这次ATP用来写C++的东西是Visual Studio。好复杂啊这玩意儿。。。难用死了QAQ

嗯前言就先说这么些叭。

##进入正题

要在VS里弄一个用OpenCV处理图像的程序出来首先得在OpenCV的工作目录下新建一个项目然后把这个项目配置好,包括设置依赖然后新建个源文件。

仍然先贴代码。

#include "cv.h"
#include "highgui.h"
#include <cstdio>
using namespace std;
IplImage *srcimage, *newimage;
int main()
{
    if ((srcimage = cvLoadImage("03.jpg", 0)) == 0) {
        printf("??!!\n");
    }
    cvNamedWindow("source", 1);
    cvShowImage("source", srcimage);
    cvSaveImage("gray.jpg", srcimage);

    cvWaitKey(0);

    cvDestroyWindow("source");
    cvReleaseImage(&srcimage);

    return 0;
}

这个程序实际上就是读入了一个图片然后把这个图片转换成黑白的然后存下来并且在另一个窗口里显示出来。

其实ATP觉得这函数名字这么长就算不知道它是啥原理大概翻译一下也知道它在干啥了。

###关于IplImage

博客园这个字体是什么鬼啊喂为什么小写L和大写I长得一模一样。。。还好代码块里面还能区分出来它是IPLIMAGE(全大写版本)

这个东西是OpenCV里面用来接收图像的数据类型。它有一大堆属性,比如是灰的还是彩的呀,图像size是多少呀之类的。不过这段代码里一个也没用到。用到了再说叭。

为啥要新建一个这个类型的指针而不新建一个这个类型的变量,是因为函数们返回的都是指针类型。。。ATP也没啥办法

比如下面那个加载图片的函数——

###关于cvLoadImage

这个函数返回一个指针指向一个IplImage类型的变量,里面存的就是加载进来的图片。

同时它还可以像上面那么用——如果图片加载失败,比如你的路径指定错了之类的话,赋值语句的返回值就是0。

函数要带两个参数,第一个字符串是图片的路径。它一开始默认是指到源文件放置的那个目录的,也就是像上面那种指定路径的方式需要把图片和main.cpp放一起才行。

还可以在源文件所在的目录下新建一个文件夹然后在路径字符串里面加上文件夹路径。

比如这样:

srcimage = cvLoadImage("image\\03.jpg", 0);

第二个参数是说明这个图片是灰的还是彩的。0代表强制转化为灰度图,1代表彩色图,-1代表按照原图来。

这里的灰色和彩色不仅仅是指它“看起来”怎么样。根本区别在于它要用单通道存还是三通道存。也就是说如果是灰度图,它的每个像素只需要一个数字描述,就是它的灰度;如果是彩色图,每个像素就需要三个数字描述,就是RGB三个数据。

就比如说如果把一个灰色的图片加载成“彩色图”的形式,计算机并不会自动给它上色(要是可以的话就上天了),它看起来还是灰色的,但是它在内部的每个像素已经需要三个数字了。

反之如果加载成“灰色图”的形式,它看起来也还是灰色的,但它内部每个像素只需要一个数字来描述。

###关于cvNamedWindow和cvShowImage

cvNamedWindow可以创建一个窗口。第一个参数就是窗口名字,第二个参数是个整数,可以不写,默认值就是1。这个参数ATP也不知道有啥作用。。。。好像跟窗口大小的调整有关?

而cvShowImage就用来在这个窗口里显示要显示的图片。第一个参数传字符串,是窗口名字;第二个参数传指针,是指向要显示的图片的。

###关于cvSaveImage

就是把某个指针指向的图片保存下来啦。第一个参数是代表路径的字符串,第二个参数传指针。(你看这玩意儿到处都是指针

###关于cvWaitKey

这个就是等用户按键用的。如果不加这个玩意儿的话程序会直接执行下去,你能看到的就只有控制台界面一闪而过了。。。

虽然这里用得像一个void函数但是这玩意儿实际上是有返回值的!返回的就是用户按下去的那个键。

里面的那个参数delay是告诉计算机要等多久的,默认值是0。如果这个数小于等于0的话程序就会一直等待下去直到用户按键为止,否则就等待delay毫秒再往下走。

###关于cvDestroyWindow和cvReleaseImage

这两个函数是每次OpenCV的程序结束了以后必须要加上的,作用分别是销毁窗口和释放图片。实际上就是内存释放,如果这两句不加的话,程序不释放内存就直接退出会报错。

cvDestroyWindow函数里面带一个字符串参数表示窗口名称,cvReleaseImage函数里面带一个指针类型变量,指向的是要释放的那个指针,也就是说它带进去的是一个指向IplImage类型指针的指针。。。看起来特别绕不过反正ATP就光记住了每次用的时候在前面加取地址符(×

##正儿八经的Lv.2

上面那个代码光把图片显示出来了但是什么也没对它做。。所以ATP把上面那个代码改了一下!

#include "cv.h"
#include "highgui.h"
#include <cstdio>
using namespace std;
IplImage *srcimage, *newimage;
int main()
{
    if ((srcimage = cvLoadImage("03.jpg", 0)) == 0) {
        printf("??!!\n");
    }
    cvNamedWindow("source", 1);
    cvShowImage("source", srcimage);

    cvWaitKey(0);

    newimage = cvCreateImage(cvGetSize(srcimage), srcimage->depth, srcimage->nChannels);
    cvFlip(srcimage, newimage, 0);
    cvSaveImage("gray.jpg", newimage);
    cvShowImage("source", newimage);

    cvWaitKey(0);

    cvDestroyWindow("source");
    cvReleaseImage(&srcimage);

    return 0;
}

这段代码实现的功能是在第一次按键以后把图片上下翻转,第二次按键的时候释放窗口并关闭。

###关于cvCreateImage

这个函数实际上可以看成是对指针变量所指向的内容初始化,相当于“new”一个东西出来。ATP一开始写的时候忘加这一句了结果运行出来的newimage就是个0kb的空图片。。

这个函数带三个参数,第一个参数要带一个cvSize类型的结构体,里面存储图片的宽和高,直接用cvGetSize函数就可以很方便地得到这个参数。

ATP一开始做的时候把它和IplImage里面的imageSize参数混了。。举个例子来讲srcimage->imageSize这个变量里面存的是一个int整型代表srcimage图像所占的字节数。

第二个参数是srcimage的一个属性,表示的是图像的“位深度”。可以理解成是用来表示一个像素的每个数据的“取值范围”。具体到它的取值什么的,OpenCV里面有规定的常量,常见的比如:

IPL_DEPTH_8U:无符号8位整型,取值范围是0~255

IPL_DEPTH_16S:有符号16位整型,取值范围是-32768~32767

还有好多别的ATP不一一列举了。

比如ATP在第一个cvWaitKey后面加了这么一句:

printf("%d\n", srcimage->depth);

ATP的代码输出了一个“8”,说明这个图像位深度是8,也就是每个像素占8个字节。

第三个参数nChannels表示的就是通道数目。也就是上面提到过的“灰色图”还是“彩色图”。

###关于cvFlip

这个函数是上面那段代码的关键部分,就是把一个图片进行翻转。

第一个参数指向原图片,第二个参数指向翻转后的图片,第三个参数代表翻转方式。0是按x轴对称,1是按y轴对称,-1是先按x轴对称再按y轴对称。

实际上这玩意儿的原理大概。。。就,按照像素访问图片然后按提前设定的映射方式变过去就好了?

然后下面就是把翻转后的图片存下来然后显示出来啦。。。。

##然后这篇文章就结束了ATP还不知道它啥时候会发出来下一篇叻。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Stella981 Stella981
3年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这