1.实验一
1.1.实验过程中遇到和解决的问题
题目:加载并显示图像
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat image = imread("D:\\cLion\\project\\image\\2.jpg");
imshow("First image", image);
waitKey(0);
}
-
imread
函数原型为imread(const string& filename, int flags=1)
- 这里的
filename
需要的是图像的路径。该函数从文件中加载图像并返回一个矩阵,如果图像不能被读取,则返回一个空的矩阵 - 这里介绍一下不同
flag
的效果-
flag=-1
:8位深度,原通道 -
flag=0
:8位深度,单通道(读取出来是灰度图) -
flag=1
:8位深度,3通道(RGB) -
flag=2
:原深度,单通道 -
flag=3
:原深度,3通道 -
flag=4
:8位深度,3通道
-
- 这里的
-
waitkey()
控制这imshow(n)
的窗口持续时间,单位是 ms,图像显示窗口将在 n ms 后关闭-
waitkey()
和waitkey(0)
都表示无限等待 - 当等待时间内无任何操作时等待结束后返回-1。
- 当等待时间内有输入字符时,则返回输入字符的ASCII码对应的十进制值
- 如果waitKey处于一个循环中,里面的参数将显示视频读取的帧(显示视频时使用)
-
1.2.结果
2.实验二
题目:实现一个读取图像任意通道的函数
2.1.实验过程中遇到和解决的问题
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
using namespace std;
using namespace cv;
void getChannel(const uchar* input, int width, int height, int inStep, int inChannels, uchar* output, int outStep, int channelToGet){
for (int y = 0; y < height; ++y, input += inStep, output += outStep){
const uchar* px = input; // 二维数组中每个一维数组的起始地址
for (int x = 0; x < width; ++x, px += inChannels)
output[x] = px[channelToGet]; //一维数组访问元素
}
}
int main()
{
Mat image = imread("D:\\cLion\\project\\image\\2.jpg");
Mat output_image(image.size(), CV_8UC1); // 将输出图像设置为单通道
getChannel(image.data, image.cols, image.rows, image.step, image.channels(), output_image.data, output_image.step, 2);
imshow("output", output_image);
waitKey(0);
}
- 这里需要注意的是,图像的
data
部分是一个二维数组,像通常的二维数组一样访问就好了 - 将输出图像设置为单通道图像操作起来更方便
- 每次都取输入和输出二维数组的起始地址(就是处理完一行后,将首地址加上
step
)- 每次都处理一行,按照访问一维数组的方式来进行赋值即可
2.2.结果
B通道:
G通道:
R通道:
3.实验三
题目:现有一张4通道透明图像 a.png
- 从其中提取出
alpha
通道并显示 - 用
alpha
混合,为透明图像替换一张新的背景
3.1.实验过程中遇到和解决的问题
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat imageA = imread("D:\\cLion\\project\\alpha.png", IMREAD_UNCHANGED); // 前景
Mat imageB = imread("D:\\cLion\\project\\sdu01.png"); // 背景
vector<Mat> mask_channels;
float alpha = 1.0;
// 分离通道
split(imageA, mask_channels); // 分离出 RGBA 分别作为一个图像
// 取出 alpha 通道
Mat mask = mask_channels[3];
imshow("alpha image", mask);
waitKey(1000); // 看个三秒
Mat mixImage(imageB.size(), CV_8UC3);
for (int i = 0; i < imageB.rows; i++)
for (int j = 0; j < imageB.cols; j++) {
if (i < imageA.rows && j < imageA.cols && mask.at<uchar>(i, j))
for(int k = 0; k < 3; k++) mixImage.at<Vec3b>(i, j)[k] = saturate_cast<uchar>(alpha * float(imageA.at<Vec4b>(i, j)[k]) + (1 - alpha) * float(imageB.at<Vec3b>(i, j)[k]));
else mixImage.at<Vec3b>(i, j) = imageB.at<Vec3b>(i, j);
}
imshow("mixed image", mixImage);
waitKey(0);
}
- 首先读进四通道图像
-
imread()
函数后面的参数是-1
或者IMREAD_UNCHANGED
时代表读入原通道,而png
图像本身就是具有alpha
通道的,所以加了这两个参数(这俩都行),就能够读入四通道图像(注意:jpg
图像是没有第四个通道的),这张作为前景图 - 背景图是否读入四通道个人认为意义不大,因为合成时是将前景图嵌入到背景图中,所以三通道就可以了。
-
split
函数的功能是进行通道分离(其实实验二的通道分离就是这个函数) - 设置一个
alpha
合成参数,当然也可以根据图像的alpha
通道值来确定 - 遍历背景图,如果当前位置前景图存在,则将前景图与背景图融合
- 注意,四通道图像访问要使用
Vec4b
,三通道图像使用的是Vec3b
-
saturate_cast
函数的功能是防止数据溢出(大于255时设置为255,小于0时设置为0) - 没有前景图的地方直接等于背景图像素就好了
- 注意,四通道图像访问要使用
-
3.2.结果
- alpha image:
文章来源:https://www.toymoban.com/news/detail-735836.html
- mixed image:
文章来源地址https://www.toymoban.com/news/detail-735836.html
到了这里,关于山东大学数字图像处理实验(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!