2018-10-31 09:57:54 wydbyxr 阅读数 341

模板匹配

  首先模板不是用来 精确定位的,只能用来粗定位。先粗定位,然后在你的当前图中扣取 和模板一样大小的区域,然后再进行精确定位。

问题1

  对于有缩放和旋转的目标你们是怎么定位的呢?
  轮廓;匹配;模板匹配

问题2

  用ORB特征匹配,怎么确定匹配到的就是我的模板图像啊 ?
  匹配后的区域进行相减或者算相似度。两图相减,注意两图的大小要一样,可现在大小就是不一样,所以我才用的ORB。

2011-08-25 18:22:46 kevinzhangyang 阅读数 14156

 

CImg 库是一个免费、开源的图像处理C++库,名称原意是 Cool Image,正如其名,CImg是一个非常优秀、功能强大、代码简洁、使用方便的C++ 图像处理库。它不仅非常适合科学家、研究生做科研时使用,也适合在工业应用工程开发中使用,更适合的是,对于有志于开发简洁、高效、功能强大的图像处理库的人而言,CImg的源码是不可多得的学习和参考资料。

  

CImg 官网:http://cimg.sourceforge.net/

CImg论坛:http://sourceforge.net/projects/cimg/forums/forum/334630

 

总体而言,CImg 有以下特征:

 

功能强大:使用CImg, 可以读取和存储各种格式的图像文件,可以访问像素值,可以显示、变换、及对图像进行各种滤波,在图像上画图像元素(字符串、多边形、3-d 物体...),计算图像的各种统计信息,处理人机交互等等...

 

普适性:CImg只定义了一个模板类来表征任何不超过4-d 的数据集,并且元素类型可以是绝大多数C++内置类型和自定义类型(bool, char, int, float...). CImg 还可以处理图像集合和图像序列。

 

可移植性:它完全兼容于操作系统如Windows, Unix, Linux, MacOS X, *BSD...,也完全兼容与编译器如 VC++, g++, icc...等,具有高度的可移植性。

 

轻便性:CImg 非常轻便,整个库只用一个文件:cimg.h。任何C++应用程序只需要将该头文件包含进工程中即可使用该库的全部功能。它只定义了四了类(模板)和两个名称空间。该库只依赖与标准C++和STL,只在显示类部分依赖与操作系统的GDI,再也不依赖任何其他的外部库。

 

可扩展性:CImg 使用两种机制来增强其功能,这两种机制都不是必须的,只是锦上添花,可以增加一些功能。一是利用外部工具或库的功能,比如:ImageMagick,GraphicsMagick,XMedCon,FFMPEG, libpng, libjpeg, libtiff, Magick++, OpenCV, Lapack, Board, OpenEXR or FFTW3;二是使用插件的机制,可以使库的使用者自行扩展库的功能。

 

自由性:完全免费、开源、可以用于商业开发。

 

跟OpenCV相比,CImg 虽然提供了基本上所有的图像处理的基本操作,但图像处理的高级操作较少,因此总体上功能比OpenCV少很多,(因为OpenCV 本身很庞大,包括基本上所有的图像处理基本操作,还包含了大量的图像处理高级操作,而且还包含了模式识别的东西)。但CImg对有志于开发图像处理库的人而言,具有很大的研究价值,因为该库结构简单,代码简洁高效,功能相对已经很强大,且代码量不大(40,000多行),编程技巧很有大师风格。 当然,如果研究者水平极高,有能力研究OpenCV源码的,则另当别论。

 

 

 

2019-12-10 15:17:17 weixin_43585712 阅读数 7

模板匹配

模板匹配顾名思义就是给定一幅影像(模板)然后在另一幅 图像中寻找这个模板的操作。它是一种用来在一幅大图中 寻找模板图像位置的方法。在OpenCV中有cv2.matchTemplate() 函数供我们方便调用。它的工作原理与2D卷积函数一样, 将模板图像在输入图像(大图)上滑动,并且在每一个位置对 模板图像和与其对应的输入图像的子区域进行比较。返回 的结果是一个灰度图像,每一个像素值表示了此区域与模板 的匹配程度。

匹配步骤

1.输入原图像(I)和模板图像(T)。在原图像中我们希望找到一块和模板匹配的区域
2.通过将模板在原图像上滑动来寻找最匹配的区域。 这里所谓的滑动是指模板图像块一次移动一个像素(从左往右,从上往下)。 在每一个位置,都进行一次度量计算,来判断该像素对应的原图像的特定区域 与模板图像的相似度。
3.对于模板T覆盖在I上的每个位置,把上一步计算的度量值保存在结果图像矩阵R中。 在R中每个位置都包含对应的匹配度量值。
4.在结果图像矩阵中寻找最值(最大或最小,根据算法不同而不同)。最值所对应的像素的位置即认为是最高的匹配。 以该点为顶点,长宽和模板大小图像一样的矩阵认为是匹配区域。在OpenCV中可以用cv2.minMaxLoc()函数获得最值坐标。

匹配算法

上面说了模板匹配的核心步骤。可以发现在步骤中有个核心问题。 那就是如何度量匹配程度,如何进行度量计算。在OpenCV中提供了 6中不同方法。这里就以这6种算法为基础介绍匹配算法。在下列公式中, T(x,y)表示模板,I(x,y)表示原图像,R(x,y)表示模板与原图相似度函数。 x、y表示某个像素,x’、y’表示循环变量,在模板那么大的范围内进行循环。
下面给出两个算法公式:
在这里插入图片描述

Opencv实现

如果输入图像大小是(W × H),模板大小是(w × h),输出结果大小就是(W-w+1, H-h+1)。 当得到这幅图之后,就可以使用函数cv2.minMaxLoc()来找到其中最小值和最大值位置了。 第一个值为矩形左上角的点(位置),(w,h)为模板矩形的宽和高。这个矩形就是找到的模板区域了。 下面是实例代码:

单个对象匹配


import numpy as np
import cv2
from matplotlib import pyplot as plt
# 依次读取原图与模板
plt.rcParams["font.family"] = "SimHei"#直接修改配置字典,设置默认字体
img = cv2.imread("E:/ruanjianDM/jupyternoerbookDM/Opencv3/data/apple.png")
template = img [100:200,0:100,:]
plt.subplot(131),plt.imshow(template[:,:,::-1])
plt.axis("off"),plt.title("模板图像")
#依次获取模板的宽高,用于后续绘制矩形
h = template.shape[0]
w = template.shape[1]
"#调用匹配函数"
# 第一个参数是原图
# 第二个参数是模板
# 第三个参数是匹配算法
# 返回的结果是一个二维的float类型的数组,大小为W-w+1 * H-h+1
res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF)

# 获取返回结果中最值及其在res中的位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

# 构造矩形并在原图上绘制
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(img, top_left, bottom_right, (255, 255, 0), 5)

# 在使用Matplotlib显示之前,需要调整BGR的顺序
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
img = cv2.merge((r, g, b))

# 打印相关信息
"可以观察到图像,模板,R矩阵的大小符合公式"
print (img.shape,template.shape,res.shape,res.dtype,cv2.minMaxLoc(res))

# 利用Matplotlib绘图对比
plt.subplot(132), plt.imshow(img)
plt.axis("off"),plt.title("原图")
plt.subplot(133), plt.imshow(res, cmap='gray')
#匹配矩阵R的信息,最亮的点认为最匹配的点
plt.axis("off"),plt.title("R图像")
plt.show()

在这里插入图片描述

多个图像匹配

在上面的例子中,原图中只出现了一次模板中的对象,但有时更有可能一幅图像中出现多个模板对象,这时就需要多对象匹配了。 在OpenCV中cv2.minMaxLoc()只会返回最值的位置。所以显然现在不能使用这个函数了。我们需要设置一个阈值,当R值大于这个 阈值时,认为是模板对象,否则不是。所以这里显然用标准化的方法更加合适,否则我们无法确定阈值。代码如下:

import cv2
from matplotlib import pyplot as plt
import numpy as np

# 依次读取原图与模板
img = cv2.imread("E:/ruanjianDM/jupyternoerbookDM/Opencv3/data/house.jpg")
template = cv2.imread("E:/ruanjianDM/jupyternoerbookDM/Opencv3/data/house1.jpg")

# 依次获取模板的宽高,用于后续绘制矩形
h = template.shape[0]
w = template.shape[1]

"调用匹配函数"
# 第一个参数是原图
# 第二个参数是模板
# 第三个参数是匹配算法
# 返回的结果是一个二维的float类型的数组,大小为W-w+1 * H-h+1
res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)

# 设定阈值
threshold = 0.8

# 从res中提取大于阈值的像素的位置
loc = np.where(res >= threshold)

# 遍历不同位置,绘制矩形
# 在函数调用中使用*list/tuple,表示将list/tuple分开,作为位置参数传递给对应函数(前提是对应函数支持不定个数的位置参数)
# 切片[::-1]是将列表或字符倒过来
for pt in zip(*loc[::-1]):
    cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)

# 在使用Matplotlib显示之前,需要调整BGR的顺序
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
img = cv2.merge((r, g, b))

# 利用Matplotlib绘图对比
plt.subplot(121), plt.imshow(res, cmap='gray')
plt.subplot(122), plt.imshow(img, cmap='gray')
plt.show()

左图是R图像,右图是匹配图像
在这里插入图片描述

2014-12-07 10:37:41 twobqn123 阅读数 475
1.使用模板处理图像相关概念:     

      模板:矩阵方块,其数学含义是卷积运算。
      卷积运算:可看作是加权求和的过程,使用到的图像区域中的每个像素分别于卷积核(权矩阵)的每个元素对应相
                乘,所有乘积之和作为区域中心像素的新值。
      卷积核:卷积时使用到的权用一个矩阵表示,该矩阵使用的图像区域大小相同,其行、列都是奇数,
              是一个权矩阵。
      卷积示例:
              3 * 3 的像素区域R与卷积核G的卷积运算:
              R5(中心像素)=R1G1 + R2G2 + R3G3 + R4G4 + R5G5 + R6G6 + R7G7 + R8G8 + R9G9
            

2.使用模板处理图像的问题:
       边界问题:当处理图像边界像素时,卷积与图像使用区域不能匹配,卷积核的中心边界像素点对应,
                 卷积运算将出现问题。
       处理办法:
              A. 忽略边界像素,即处理后的图像将丢掉这些像素。
              B. 保留原边界像素,即copy边界像素到处理后的图像

3.常用模板


如果你刚刚接触图像处理,或者离开大学很长时间,看到卷积这个东西,肯定和我样感到晕菜.那么就复习下,并且实际的写个程序验证下,我保证你这辈子不会再忘记卷积的概念了.我们来看卷积的概念.
连续空间的卷积定义是 f(x)g(x)的卷积是 f(t-x)g(x) 在t从负无穷到正无穷的积分值.t-x要在f(x)定义域内,所以看上去很大的积分实际上还是在定范围的.
实际的过程就是f(x) 先做一个Y轴的反转,然后再沿X轴平移t就是f(t-x),然后再把g(x)拿来,两者乘积的值再积分.想象下如果g(x)或者f(x)是个单位的阶越函数. 那么就是f(t-x)g(x)相交部分的面积.这就是卷积了.
把积分符号换成求和就是离散空间的卷积定义了.那么在图像卷积卷积地是什么意思呢,就是图像就是图像f(x),模板是g(x),然后将模版g(x)在模版中移动,每到一个位置,就把f(x)g(x)的定义域相交的元素进行乘积并且求和,得出新的图像一点,就是被卷积后的图像. 模版又称为卷积核.卷积核做一个矩阵的形状.
卷积定义上是线性系统分析经常用到的.线性系统就是一个系统的输入和输出的关系是线性关系.就是说整个系统可以分解成N多的无关独立变化,整个系统就是这些变化的累加.
如 x1->y1, x2->y2; 那么A*x1 + B*x2 -> A*y1 + B*y2 这就是线性系统. 表示一个线性系统可以用积分的形式 如 Y = Sf(t,x)g(x)dt S表示积分符号,就是f(t,x)表示的是A B之类的线性系数.
看上去很像卷积呀,,对如果f(t,x) = F(t-x) 不就是了吗.从f(t,x)变成F(t-x)实际上是说明f(t,x)是个线性移不变,就是说 变量的差不变化的时候,那么函数的值不变化. 实际上说明一个事情就是说线性移不变系统的输出可以通过输入和表示系统线性特征的函数卷积得到.

2015-05-26 16:00:32 qq_26267811 阅读数 228

IOS中提取图像的一般类是UIImage,其中图像原始数据的存储方式为RGBARGBARGBA(A-alpha),进行一般的图像处理需要对其进行图像原始数据提取,具体代码为:

//功能:将IOS中的UIImage图像数据转换为rgbrgbrgb格式
//参数说明
//(UIImage*)image -- UIImage图像数据
//rgb_data :(unsigned char*)rgb_data -- 转换后的rgbrgb格式的图像数据


- (void)getRGBAsFromImage:(UIImage*)image rgb_data :(unsigned char*)rgb_data      //height * width * 3
{
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
   CGContextRef context =  CGBitmapContextCreate(rawData, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    // Now your rawData contains the image data in the RGBA8888 pixel format.
    for (int i = 0 ; i < height * width; ++i)
    {
        rgb_data[i * 3 + 0] = rawData[i * 4 + 0]; //r
        rgb_data[i * 3 + 1] = rawData[i * 4 + 1]; //g
        rgb_data[i * 3 + 2] = rawData[i * 4 + 2]; //b
        //rawData[i * 4 + 3]; alpha
        
    }
    
    free(rawData);
}



//实例
- (void)viewDidLoad {
    [super viewDidLoad];
    UIImage *img = [UIImage imageNamed:@"1420268351640.jpg"];
    UIImageView *imgV= [[UIImageView alloc]initWithImage:img];
    unsigned char *rawData = (unsigned char*) calloc(imgWH * 3, sizeof(unsigned char));
    [self getRGBAsFromImage:img rgb_data:rawData];
    int vertex[8];
    int text_input[4];

    text_input[0] = 83;
    text_input[1] = 557;
    text_input[2] = 586;
    text_input[3] = 693;
    NSLog(@"imgH %f,imgW %f",imgV.frame.size.height,imgV.frame.size.width);
    card_detect_IO(rawData,imgV.frame.size.height , imgV.frame.size.width, text_input, vertex);

    
    int top_left_x, top_left_y, top_right_x, top_right_y, bottom_right_x, bottom_right_y, bottom_left_x, bottom_left_y;
    top_left_x = vertex[0];
    top_left_y = vertex[1];
    top_right_x = vertex[2];
    top_right_y = vertex[3];
    bottom_right_x = vertex[4];
    bottom_right_y = vertex[5];
    bottom_left_x = vertex[6];
    bottom_left_y = vertex[7];
    
    for(int i = 0 ; i<8 ;i++)
    {
        NSLog(@"%d  ",vertex [i]);
    }
    free(rawData);
} 


//功能:将unsigned char(rgbrgb)图像原始数据转换为UIImage格式
//参数说明:
//    输入参数: rawData rgb彩色图像原始数据(24位存储一个像素,rgbrgb存储格式)
//               height  rgb图像高度
//               width   rgb图像宽度
//    返回参数: UIImage*  返回UIIImage格式
- (UIImage*)imageFromRGB:(unsigned char*)rawData width:(int)width height:(int)height
{
    const size_t bufferLength = width * height * 3;
    NSData *data = [NSData dataWithBytes:rawData length:bufferLength];
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);
    
    // Creating CGImage from cv::Mat
    CGImageRef imageRef = CGImageCreate(width,          //width
                                        height,         //height
                                        8,              //bits per component
                                        24,             //bits per pixel
                                        width * 3,      //bytesPerRow
                                        colorSpace,     //colorspace
                                        kCGBitmapByteOrderDefault ,// bitmap info
                                        provider,               //CGDataProviderRef
                                        NULL,                   //decode
                                        false,                  //should interpolate
                                        kCGRenderingIntentDefault   //intent
                                        );
    
    // Getting UIImage from CGImage
    UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpace);
    
    return finalImage;
}




C#图像处理模板

阅读数 531

没有更多推荐了,返回首页