2014-10-16 15:47:37 u014033518 阅读数 921
  • 学习OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频教程

    OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频培训课程概况:教程中会讲解到基于opencv视频和摄像机录制、播放和播放进度控制,多视频图像合并、多视频图像融合、剪切、视频亮度、对比度、尺寸(近邻插值(手动实现),双线性插值,图像金字塔)、颜色格式(灰度图,二值化(阈值)),旋转镜像,视频裁剪(ROI),视频水印(ROI+weight),导出处理后的视频(包含音频,使用ffmpeg工具对音频进行抽取、剪切和终于opencv处理的视频合并)。

    19599 人正在学习 去看看 夏曹俊

灰度阈值变换

阈值:又称临界值,在临界范围内使用一种方法,在临界范围外使用另一种方法

y=(x>T)?255:0               T:阈值

LPSTR  lpDIBBits;	//指向源DIB图像的指针
long	lWidth;		//源图像宽度
long	lHeight;	//源图像高度
BYTE	T;			//阈值

//------------------------------

for(int i=0;i<lHeight;i++)
	for(int j=0;j<lWidth;j++)
	{
		lpSrc=(unsighned char *)lpDIBBits+lLineBytes*(lHeight-1-i)+j;//lpDIBBits[i][j]
		if(DB>T)
			*lpSrc=255; 
		else 
			*lpSrc=0;
	}//for_j


2010-05-26 21:36:00 yangfenghero 阅读数 1178
  • 学习OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频教程

    OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频培训课程概况:教程中会讲解到基于opencv视频和摄像机录制、播放和播放进度控制,多视频图像合并、多视频图像融合、剪切、视频亮度、对比度、尺寸(近邻插值(手动实现),双线性插值,图像金字塔)、颜色格式(灰度图,二值化(阈值)),旋转镜像,视频裁剪(ROI),视频水印(ROI+weight),导出处理后的视频(包含音频,使用ffmpeg工具对音频进行抽取、剪切和终于opencv处理的视频合并)。

    19599 人正在学习 去看看 夏曹俊

   阈值变换在图像处理中有着非常高的作用,很多处理都会用到。最常见的应用就是产生黑白图。

   代码如下:

  

2018-03-18 23:32:30 weixin_38757342 阅读数 2207
  • 学习OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频教程

    OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频培训课程概况:教程中会讲解到基于opencv视频和摄像机录制、播放和播放进度控制,多视频图像合并、多视频图像融合、剪切、视频亮度、对比度、尺寸(近邻插值(手动实现),双线性插值,图像金字塔)、颜色格式(灰度图,二值化(阈值)),旋转镜像,视频裁剪(ROI),视频水印(ROI+weight),导出处理后的视频(包含音频,使用ffmpeg工具对音频进行抽取、剪切和终于opencv处理的视频合并)。

    19599 人正在学习 去看看 夏曹俊

灰度的阈值变换是指将一幅灰度图像变为黑白二值图像,首先指定一个阈值,如果图像中的某像素值小于这个阈值,则将该像素的灰度值设置为0,否则,将该像素的灰度值设置为255。

关于阈值的选取有多种方法。


2019-03-29 20:51:13 Tifa_Best 阅读数 212
  • 学习OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频教程

    OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频培训课程概况:教程中会讲解到基于opencv视频和摄像机录制、播放和播放进度控制,多视频图像合并、多视频图像融合、剪切、视频亮度、对比度、尺寸(近邻插值(手动实现),双线性插值,图像金字塔)、颜色格式(灰度图,二值化(阈值)),旋转镜像,视频裁剪(ROI),视频水印(ROI+weight),导出处理后的视频(包含音频,使用ffmpeg工具对音频进行抽取、剪切和终于opencv处理的视频合并)。

    19599 人正在学习 去看看 夏曹俊

要求

  1. 利用 OpenCV 读取图像。
    具体内容:用打开 OpenCV 打开图像,并在窗口中显示
  2. 灰度图像二值化处理
    具体内容:设置并调整阈值对图像进行二值化处理。
  3. 灰度图像的对数变换
    具体内容:设置并调整 r 值对图像进行对数变换。
  4. 灰度图像的伽马变换
    具体内容:设置并调整γ值对图像进行伽马变换。
  5. 彩色图像的补色变换
    具体内容:对彩色图像进行补色变换。

过程

灰度变换

灰度变换的定义域和值域应该相等吧。

伽马变换: s=crγr[0,1]s=cr^\gamma \qquad r\in[0,1]

对数变换: s=clogv+1(1+vr)r[0,1]s=c\log_{v+1}(1+vr)\qquad r\in[0,1]

C++的functional库

整个处理流程大致相同,只有几个变换公式不同,所以把公共部分抽象出来成为一个函数,在每个变换中调用公共处理函数。

之前打算因为几个变换的函数实现中的参数个数不同,所以打算用bind的,后来发现lambda更简洁实用些。

function基本上代替了函数指针。

虽然花费了不少时间,但算是搞懂了function、bind和lambda的区别与用法。

代码

注意:补色被我理解成反色了,代码中的这个实现错误我也懒得改了。。。

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

#include <string>
#include <iostream>
#include <functional>

using namespace cv;
using namespace std;

void apply_LUT(Mat &src, Mat &dst, function<uchar(uchar)> pf)
{
    CV_Assert(src.depth() == CV_8U);

    Mat lookUpTable(1, 256, CV_8U);
    uchar* p = lookUpTable.ptr();
    for(int i = 0; i < 256; ++i)
        p[i] = pf(i);
    LUT(src, lookUpTable, dst);
    imshow("image", dst);
    waitKey(0);
}
void threshold_transform(Mat &src, Mat &dst, uchar thre)
{
    auto fun = [=](uchar r) -> uchar {return ((r > thre) ? 1 : 0) * 255;};
    apply_LUT(src, dst, fun);
}

// $s=cr^\gamma \qquad r\in[0,1]$
void gamma_transform(Mat &src, Mat &dst, float g=2, float c = 1.0)
{
    auto fun = [=](uchar r) -> uchar {return (c * pow(r/255., g)*255);};
    apply_LUT(src, dst, fun);
}

// $s=c\log_{v+1}(1+vr)\qquad r\in[0,1]$
void log_transform(Mat &src, Mat &dst, float v=1, float c=1)
{
    auto fun = [=](uchar r) -> uchar {
        return (c * 255. * log(1. + v*r/255.) / log(v + 1));};
    apply_LUT(src, dst, fun);
}

void inv_transform(Mat &src, Mat &dst)
{
    auto fun = [=](uchar r) -> uchar {return (255 - r);};
    apply_LUT(src, dst, fun);
}

int main (int argc, char **argv)
{
    String image_name((argc>1)?(argv[1]):("img_test.jpg"));
    Mat image, image_gray, image_dst;
    image = imread(image_name, IMREAD_COLOR);
    if (image.empty()) {
        cout << "Cannot read image: " << image_name << std::endl;
        return -1;
    }   
    cvtColor(image, image_gray, CV_BGR2GRAY);

    namedWindow("image", CV_WINDOW_AUTOSIZE);
    cout << "image origin" << endl;
    imshow("image", image);
    waitKey(0);

    cout << "image gray" << endl;
    imshow("image", image_gray);
    waitKey(0);

    cout << "image threshold" << endl;
    // threshold(image_gray, image_dst, 128, 255, THRESH_BINARY);
    threshold_transform(image_gray, image_dst, 128);

    cout << "image log" << endl;
    log_transform(image_gray, image_dst, 7);

    cout << "image gamma" << endl;
    gamma_transform(image_gray, image_dst, 9);

    cout << "image inv" << endl;
    inv_transform(image, image_dst);

    return 0;
}
2018-07-04 21:37:59 qq_40962368 阅读数 11014
  • 学习OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频教程

    OpenCV3.2+QT5+ffmpeg实战开发视频编辑器视频培训课程概况:教程中会讲解到基于opencv视频和摄像机录制、播放和播放进度控制,多视频图像合并、多视频图像融合、剪切、视频亮度、对比度、尺寸(近邻插值(手动实现),双线性插值,图像金字塔)、颜色格式(灰度图,二值化(阈值)),旋转镜像,视频裁剪(ROI),视频水印(ROI+weight),导出处理后的视频(包含音频,使用ffmpeg工具对音频进行抽取、剪切和终于opencv处理的视频合并)。

    19599 人正在学习 去看看 夏曹俊

图像的阈值处理

      一幅图像包括目标物体、背景还有噪声,要想从多值的数字图像中直接提取出目标物体,常用的方法就是设定一个阈值T,用T将图像的数据分成两部分:大于T的像素群和小于T的像素群。这是研究灰度变换的最特殊的方法,称为图像的二值化(Binarization)。

       阈值分割法的特点是:适用于目标与背景灰度有较强对比的情况,重要的是背景或物体的灰度比较单一,而且总可以得到封闭且连通区域的边界。

(一)简单阈值

选取一个全局阈值,然后就把整幅图像分成非黑即白的二值图像。

函数为cv2.threshold( )

这个函数有四个参数,第一个是原图像矩阵,第二个是进行分类的阈值,第三个是高于(低于)阈值时赋予的新值,第四个是一个方法选择参数,常用的有:

  • cv2.THRESH_BINARY(黑白二值)
  • cv2.THRESH_BINARY_INV(黑白二值翻转)
  • cv2.THRESH_TRUNC(得到额图像为多像素值)
  • cv2.THRESH_TOZERO(当像素高于阈值时像素设置为自己提供的像素值,低于阈值时不作处理)
  • cv2.THRESH_TOZERO_INV(当像素低于阈值时设置为自己提供的像素值,高于阈值时不作处理)

这个函数返回两个值,第一个值为阈值,第二个就是阈值处理后的图像矩阵。

img = cv2.imread('4.jpg', 0)
ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)  # binary (黑白二值)
ret, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)  # (黑白二值反转)
ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)  # 得到的图像为多像素值
ret, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)  # 高于阈值时像素设置为255,低于阈值时不作处理
ret, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)  # 低于阈值时设置为255,高于阈值时不作处理

print(ret)

cv2.imshow('thresh1', thresh1)
cv2.imshow('thresh2', thresh2)
cv2.imshow('thresh3', thresh3)
cv2.imshow('thresh4', thresh4)
cv2.imshow('thresh5', thresh5)
cv2.imshow('grey-map', img)
cv2.waitKey(0)
cv2.destroyAllWindows()


(二)自适应阈值

一中的简单阈值是一种全局性的阈值,只需要设定一个阈值,整个图像都和这个阈值比较。而自适应阈值可以看成一种局部性的阈值,通过设定一个区域大小,比较这个点与区域大小里面像素点 的平均值(或者其他特征)的大小关系确定这个像素点的情况。使用的函数为:

# 第一个参数为原始图像矩阵,第二个参数为像素值上限,第三个是自适应方法(adaptive method):
#                                              -----cv2.ADAPTIVE_THRESH_MEAN_C:领域内均值
#                                              -----cv2.ADAPTIVE_THRESH_GAUSSIAN_C:领域内像素点加权和,权重为一个高斯窗口
# 第四个值的赋值方法:只有cv2.THRESH_BINARY和cv2.THRESH_BINARY_INV
# 第五个Block size:设定领域大小(一个正方形的领域)
# 第六个参数C,阈值等于均值或者加权值减去这个常数(为0相当于阈值,就是求得领域内均值或者加权值)

# 这种方法理论上得到的效果更好,相当于在动态自适应的调整属于自己像素点的阈值,而不是整幅图都用一个阈值

img = cv2.imread('4.jpg', 0)
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# 第一个参数为原始图像矩阵,第二个参数为像素值上限,第三个是自适应方法(adaptive method):
#                                              -----cv2.ADAPTIVE_THRESH_MEAN_C:领域内均值
#                                              -----cv2.ADAPTIVE_THRESH_GAUSSIAN_C:领域内像素点加权和,权重为一个高斯窗口
# 第四个值的赋值方法:只有cv2.THRESH_BINARY和cv2.THRESH_BINARY_INV
# 第五个Block size:设定领域大小(一个正方形的领域)
# 第六个参数C,阈值等于均值或者加权值减去这个常数(为0相当于阈值,就是求得领域内均值或者加权值)
# 这种方法理论上得到的效果更好,相当于在动态自适应的调整属于自己像素点的阈值,而不是整幅图都用一个阈值
th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 5, 2)
th3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
th4 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
cv2.imshow('img', img)
cv2.imshow('th1', th1)
cv2.imshow('th2', th2)
cv2.imshow('th3', th3)
cv2.imshow('th4', th4)
cv2.waitKey(0)
cv2.destroyAllWindows()


对于第五个参数的窗口越来越小时,发现得到的图像越来越细了,可以设想,如果把窗口设置的足够大的话(不能超过图像大小),那么得到的结果可能就和第二幅图像的相同了。

(三)Otsu's二值化

cv2.threshold( )函数有两个返回值,一个是阈值,第二个是处理后的图像矩阵。

前面对于阈值的设定上,我们选择的阈值都是127,在实际情况中,有的图像阈值不是127得到的图像效果更好。那么这里就需要算法自己去寻找一个阈值,而Otsu's就可以自己找到一个认为最好的阈值。并且Otsu's非常适合于图像灰度直方图(只有灰度图像才有)具有双峰的情况。他会在双峰之间找到一个值作为阈值,对于非双峰图像,可能并不是很好用。那么经过Otsu's得到的那个阈值就是函数cv2.threshold的第一个参数了。因为Otsu's方法会产生一个阈值,那么函数cv2.threshold( )的第二个参数(设定阈值)就是0了,并且在cv2.threshold的方法参数中还得加上语句cv2.THRESH_OTSU.

在下列这些程序和图片中大家会有鲜明的体会:

img = cv2.imread('2.jpg', 0)
ret1, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)  # 简单滤波
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)  # Otsu 滤波
print(ret2)
cv2.imshow('img', img)
cv2.imshow('th1', th1)
cv2.imshow('th2', th2)
# 用于解决matplotlib中显示图像的中文乱码问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.hist(img.ravel(), 256)
plt.title('灰度直方图')
plt.show()
cv2.waitKey(0)
cv2.destroyAllWindows()



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