CV+openCV 之操作图像(中)

1. 用迭代器扫描图像

        【准备工作】使用操作图像(上)的减色程序作为例子。

        【实现】

#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include<iostream>
#include<random>
using namespace std;
using namespace cv;
void colorReduce(cv::Mat &image, int div = 64) {
	//div必须是2的幂
	int n = static_cast<int>(
		log(static_cast<double>(div)) / log(2.0) + 0.5);
	//用来截取像素值的掩码
	uchar mask = 0xFF << n;//如果div=16,mask=0xF0
	uchar div2 = div >> 1;//div2=div/2
	//迭代器
	cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>();
	cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>();

	//扫描全部像素
	for (; it != itend; ++it) {
		(*it)[0] &= mask;
		(*it)[0] += div2;
		(*it)[1] &= mask;
		(*it)[1] += div2;
		(*it)[2] &= mask;
		(*it)[2] += div2;
	}
}
int main()
{
	cv::MatIterator_<cv::Vec3b> it;//或者 cv::Mat_<cv::Vec3b>::iterator it;
	cv::Mat image;
	image = cv::imread("1.jpg");
	//复制图像,深复制最简单的是使用clone
	cv::Mat imageClone = image.clone();
	//处理图像副本
	colorReduce(imageClone, 64);
	cv::namedWindow("Image");
	cv::imshow("Image", imageClone);
	cv::waitKey(0);
}

        【实现原理】

        不管扫描的是哪种类型的集合,使用迭代器时总是遵循同样的模式。

         首先要使用合适的专用类创建迭代器对象,这里是cv::Mat_::iterator(或 cv::MatIterator_)。 然后可以用 begin 方法,在开始位置(本例中为图像的左上角)初始化迭代器。

        对于彩色 图像的 cv::Mat 实例,可以使用 image.begin()。

        还可以在迭代器上使用数学计算,若要从图像第二行开始,可以用 image.begin()+image.cols 初始化 cv::Mat 迭代器。获取集合结束位置的方法也类似,只是改用 end 方法。但是,若用 end 方法得到的迭代器已经超出了集合范围,因此必须在结束位置停止迭代过程。结束的迭代器也能使用数学计算,例如你想在最后一行前就结束迭代,可使用 image.end()-image.cols。 初始化迭代器后,建立一个循环遍历所有元素,到结束迭代器为止。

        典型的 while 循环就 像这样:

while (it!= itend) {
    // 处理每个像素 --------------------- 
    ... 
    // 像素处理结束 --------------------- 
    ++it; }

         可以用运算符++移动到下一个元素,也可以指定更大的步幅。例如 it+=10,对每10个像素处理一次。 最后,在循环内部使用取值运算符*访问当前元素,可以用它来读(例如 element= *it;)或写(例如*it= element;)。也可以创建常量迭代器,用作对常量 cv::Mat 的引用, 或者表示当前循环不修改cv::Mat实例。常量迭代器定义:cv::MatConstIterator_ it; 或者:cv::Mat_::const_iterator it;

        【扩展阅读】

//也可以用对cv::Mat_实例的引用来获取开始与结束位置
cv::Mat_<cv::Vec3b> cimage(image); 
cv::Mat_<cv::Vec3b>::iterator it= cimage.begin(); 
cv::Mat_<cv::Vec3b>::iterator itend= cimage.end();

2. 编写高效的图像扫描循环

        【实现】

    const int64 start = cv::getTickCount();//测算运行时间的函数
	colorReduce(imageClone, 64);//调用函数
	//经过的时间(秒)
	double duration = (cv::getTickCount() - start) / cv::getTickFrequency();
	std::cout << duration;

        【实现原理】

        colorReduce函数使用位运算的方法要比其他方法快得多。使用迭代器的主要目的是简化图像扫描 过程,降低出错的可能性,但是运行时间更长。

        对于可以预先计算的数值,要避免在循环中做重复计算。

        之前还做过连续性测试,针对连续图像生成一个循环,而不是对行和列运行常规的二重循环, 使运行速度平均提高了 10%。

3. 扫描图像并访问相邻像素

        【准备工作】本例将使用锐化图像的处理函数。

        【实现】

#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include<iostream>
#include<random>
using namespace std;
using namespace cv;
void sharpen(const cv::Mat& image, cv::Mat& result) {
	//判断是否需要分配图像数据,如果需要就分配
	result.create(image.size(), image.type());
	int nchannels = image.channels();//获得通道数
	//处理所有行(除了第一行和最后一行)
	for (int j = 1; j < image.rows - 1; j++) {
		const uchar* previous = image.ptr<const uchar>(j - 1);//上一行
		const uchar* current = image.ptr<const uchar>(j);     //当前行
		const uchar* next = image.ptr<const uchar>(j + 1);    //下一行

		uchar* output = result.ptr<uchar>(j);//输出行

		for (int i = nchannels; i < (image.cols - 1) * nchannels; i++) {
			//应用锐化算子
			*output++ = cv::saturate_cast<uchar>(
				5 * current[i] - current[i - nchannels] -
				current[i + nchannels] - previous[i] - next[i]);
		}
	}
	result.row(0).setTo(cv::Scalar(0));
	result.row(result.rows - 1).setTo(cv::Scalar(0));
	result.col(0).setTo(cv::Scalar(0));
	result.col(result.cols - 1).setTo(cv::Scalar(0));
}
int main()
{
	cv::MatIterator_<cv::Vec3b> it;//或者 cv::Mat_<cv::Vec3b>::iterator it;
	cv::Mat image;
	image = cv::imread("1.jpg");
	//复制图像,深复制最简单的是使用clone
	cv::Mat imageClone = image.clone();
	sharpen(image, imageClone);//调用函数
	cv::namedWindow("Image");
	cv::imshow("Image", imageClone);
	cv::waitKey(0);
}

        【实现原理】

        计算锐化数值的方法:

        sharpened_pixel= 5*current-left-right-up-down;

        只需定义额外的指针,并与当前行的指针一起递增, 然后就可以在扫描循环内访问上下行的指针了。

        调用 cv::saturate_cast 模板函数,并传入运算结果,来计算输出像素的值。因为计算像素的数学表达式的结果经常超出允许的范围(即小于 0 或大于 255)。使用这 函数可把结果调整到 8 位无符号数的范围内,具体做法是把小于 0 的数值调整为 0,大于 255 的 数值调整为 255。

        由于边框上的像素没有完整的相邻像素,因此不能用前面的方法计算。这里简单地把它们设置为 0。有时也可以对这些像素做特殊的计算,但在大多数情况下,花时间处理这些极少数像素是没有意义的。在本例中,用两个特殊的方法把边框的像素设置为了 0,它们是 row 和 col。这两个方法返回一个特殊的 cv::Mat 实例,其中包含一个单行 ROI(或单列 ROI),具体范围取决于参数。这里没有进行复制,因为只要这个一维矩阵的元素被修改,原始图像也会被修改。用 setTo 方法来实现这个功能,此方法将对矩阵中的所有元素赋值: result.row(0).setTo(cv::Scalar(0)); 这个语句把结果图像第一行的所有像素设置为 0。对于三通道彩色图像,需要使用 cv:: Scalar(a,b,c)来指定三个数值,分别对像素的每个通道赋值。

        【扩展阅读】

        用滤波去处理图像,锐化就显得非常简单了。

void sharpen(const cv::Mat& image, cv::Mat& result) {
	// 构造内核(所有入口都初始化为 0)
	cv::Mat kernel(3, 3, CV_32F, cv::Scalar(0));
	// 对内核赋值
	kernel.at<float>(1, 1) = 5.0;
	kernel.at<float>(0, 1) = -1.0;
	kernel.at<float>(2, 1) = -1.0;
	kernel.at<float>(1, 0) = -1.0;
	kernel.at<float>(1, 2) = -1.0;
	// 对图像滤波
	cv::filter2D(image, result, image.depth(), kernel);
}

        在对像素邻域进行计算时,通常用一个核心矩阵来表示。这个核心矩阵展现了如何将与计算 相关的像素组合起来,才能得到预期结果。而本例中的核心矩阵为:

                ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​     

        鉴于滤波是图像处理中的常见操作,OpenCV 专门为此定义了一个函数,即 cv::filter2D。 要使用这个函数,只需要定义一个内核(以矩阵的形式),调用函数并传入图像和内核,即可返 回滤波后的图像。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: QT是一种跨平台的开发框架,可以用来开发各种应用程序。OpenCV是一个开源的计算机视觉库,可以用来处理图像和视频等图像处理任务。OCR(Optical Character Recognition)库是一种能够读取图像文字并将其转换为可编辑文本的技术。 在使用QT和OpenCV来开发一个汉字识别的图像演示程序时,我们可以按照以下步骤进行: 1. 首先,需要创建一个QT项目,并添加OpenCV的库文件和头文件,以便在项目使用OpenCV功能。 2. 然后,需要加载待识别的图像文件。可以使用QT的图像处理功能加载图像文件,并在QT的图形界面显示出来。 3. 接下来,我们可以使用OpenCV图像处理功能对加载的图像进行预处理,以提高识别准确度。例如,可以使用图像平滑、二值化等技术来消除噪声和增强图像的对比度。 4. 然后,我们可以使用OCR库来识别图像的汉字。OCR库可以通过训练和学习,识别不同的汉字字符。可以使用OCR库提供的API来调用该功能,并将识别结果返回给应用程序。 5. 最后,我们可以将识别的汉字结果显示在QT的图形界面,以便用户查看和编辑。可以使用QT的文本框组件来显示识别出的文字,并提供其他相关的编辑功能。 通过以上步骤,我们可以完成一个简单的QT和OpenCV结合的汉字识别图像演示程序。用户可以通过该程序加载图像文件,并对图像的汉字进行识别和编辑。这个演示程序可以为用户展示汉字识别的基本原理和功能,并为用户提供一个直观的界面来操作和体验。 ### 回答2: Qt是一种跨平台的C++应用程序开发框架,OpenCV是一个用于图像处理和计算机视觉的开源库,OCR(Optical Character Recognition)是光学字符识别的缩写,用于将印刷体文字转化为可编辑的电子文字。 要实现在Qt使用OpenCV进行OCR汉字识别,可以按照以下步骤进行: 1. 准备样本数据集:收集一些包含汉字的图像样本,包括不同字体、大小和倾斜度的样本,用于训练和测试OCR模型。 2. 安装OpenCV和Qt:下载并安装OpenCV和Qt开发环境,确保能够在Qt调用OpenCV库。 3. 加载样本数据集:使用OpenCV读取样本数据集图像文件,并将其转换为适合进行OCR处理的数据格式。 4. 预处理图像:对加载的图像进行预处理,例如灰度化、二值化、降噪等操作,以提高OCR的识别准确性。 5. 训练OCR模型:使用OpenCV的机器学习算法,如支持向量机(SVM)或卷积神经网络(CNN),对预处理后的图像进行训练,以建立用于识别汉字的模型。 6. 图像识别:使用训练好的OCR模型对待识别的图像进行处理,提取其的汉字信息,并将其转化为可编辑的电子文字。 7. 在Qt界面展示结果:将识别到的汉字结果显示在Qt的界面,以供用户查看和编辑。 通过以上步骤,我们可以在Qt使用OpenCV库进行OCR汉字识别的演示。用户可以加载图像,点击识别按钮后,程序将自动进行图像处理和汉字识别,并将结果显示在界面上。这样,用户可以方便地通过这个演示程序了解OCR汉字识别的基本原理和实现方式。 ### 回答3: QT是一种流行的跨平台应用程序开发框架,而OpenCV是一个广泛使用的计算机视觉库。OCR(Optical Character Recognition)库可以用于识别图像的文字。下面是一个300字的文回答,旨在介绍如何在QT使用OpenCV和OCR库来实现汉字识别的演示程序。 首先,我们需要在QT项目集成OpenCV库。可以通过在项目文件添加OpenCV相关的库路径和头文件路径来实现。然后,在QT项目创建一个窗口,将图像显示在窗口上。 接下来,我们需要加载要识别的图像。使用OpenCV的函数,我们可以读取图像文件,并将其转换为OpenCV的Mat对象。然后,我们可以将Mat对象转换为QT图像对象,以便在QT窗口显示。 在加载图像后,我们可以使用OCR库来识别其的汉字。OCR库可以读取OpenCV的Mat对象,然后将其转换为文本。 为了在QT使用OCR库,可能需要对其进行一些设置和配置。这包括选择合适的OCR引擎,以及设置字库和语言。这些设置可能因库的不同而有所不同,可参考OCR库的文档以获取详细的配置信息。 一旦配置完毕,我们可以调用OCR库的识别函数,将图像传递给它。OCR库将扫描图像,并将识别结果返回为文本。我们可以在QT窗口显示这些识别结果。 最后,我们可以通过增加一些用户交互功能来改进演示程序。例如,我们可以添加一个按钮,使用户能够选择不同的图像进行识别。我们还可以让用户可以调整OCR库的一些参数,以改进识别的准确性。 总之,通过集成OpenCV和OCR库,我们可以在QT开发一个简单的汉字识别演示程序。这个演示程序可以加载图像,调用OCR库来识别汉字,并在QT窗口显示识别结果。同时,我们可以通过增加一些用户交互功能来提高演示程序的实用性和可定制性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值