3

全流程机器视觉工程开发(三)任务前瞻 - 从opencv的安装编译说起,到图像增强和分割...

 7 months ago
source link: https://www.cnblogs.com/Leventure/p/18000292
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

全流程机器视觉工程开发(三)任务前瞻 - 从opencv的安装编译说起,到图像增强和分割

最近开始做这个裂缝识别的任务了,大大小小的问题我已经摸得差不多了,然后关于识别任务和分割任务我现在也弄的差不多了。

现在开始做正式的业务,也就是我们说的裂缝识别的任务。作为前言,先来说说场景:

现在相机返回过来的照片:

  1. 都是jpeg格式的照片,当然也可能是别的格式,目前主流是jpeg格式
  2. 大小约为11mb-14mb左右
  3. 图片大小为5120x5120

我们现在如果说想直接使用这个图片来进行图片识别的话,会有很多的问题。其中最主要的问题就是图片实在是过大,5120x5120的图片会导致图片不论是训练还是推理期都太长了,并且为了更好地处理图片,我们都会要求图片的训练期和推断图片都必须是比较小的,这样才有利于我们后续不论是实例分割还是目标识别任务。

前言说了,我们的目标主要是两个,那就是

  1. 将现有图片分割成1280 * 1280 的小块。
    为什么这么做?因为我们的图片边界刚好是5120,5120 / 4 = 1280,也就是说我们要把原先一张照片切成 4 * 4 = 16块

  2. 将现有图片全部增亮
    这里需要注意一点,就是在增亮图片的同时,不能让图片过曝。这里我们需要做一点特殊的处理,下文中会说。

既然有了目标,那么我们就来一步步写实现。这里因为我们后续要使用opencv等各种库,所以从现在开始我们所有的c++项目统一使用cmake管理。

那么在正式开始之前,我们需要准备opencv环境

这里可以参考以下文章
windows下安装Visual Studio + CMake+OpenCV + OpenCV contrib+TensorRT
有关cmake编译与安装opencv的内容,我觉得是比较中肯的,这里因为我已经安装好了opencv,就不再重复这个内容了。

那么现在默认就是大伙已经安装上了opencv 了,那么我这里就开始写图像分割和增强了。

首先使用vs 2022新建一个cmake项目:

在这里插入图片描述

创建完毕后,打开cmake gui程序

在这里插入图片描述

这里我使用vs 2022来编译和管理这个项目,点击configure,然后再点击gernerate,这样一个空项目就被我编辑出来了,就在我们的build目录下

在这里插入图片描述

点击Lev_PictureManager.sln进入项目管理。

在这里插入图片描述

当然了,我这里开发的这个工程是需要以后去做移植的,所以肯定是做成dll的,这个有关图形的库后续我也会做一些更新,相当于是一个自己的小工具箱,所以为了更好的使用这里需要修改一下 cmake 工程

Lev_PictureManager的CMakeList.txt改成这样,每一条为什么这么改我都写在了注释里面,可以看看

# CMakeList.txt: Lev_PictureManager 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#
#如果环境变量中没有声明opencv的路径则需要加上这一条,如果加上了则无所谓
set(OpenCV_DIR C:\\Program Files (x86)\\opencv\\build)
#找到opencv 的 package
find_package(OpenCV REQUIRED)
#引入opencv的头文件
include_directories(${OpenCV_INCLUDE_DIRS})
#导出windows下的.lib静态链接库用以链接符号
set(WINDOWS_EXPORT_ALL_SYMBOLS ON)
# 导出为动态链接库的形式
add_library (Lev_PictureManager SHARED "Lev_PictureManager.cpp" "Lev_PictureManager.h")
#链接到opencv的.lib文件
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBRARIES})

if (CMAKE_VERSION VERSION_GREATER 3.12)
  set_property(TARGET Lev_PictureManager PROPERTY CXX_STANDARD 20)
endif()

# TODO: 如有需要,请添加测试并安装目标。

接下来在项目中编译一下这个CMakeList.txt,再尝试在头文件中引入

#include "opencv2/opencv.hpp"

如果引入成功,则说明调用是成功的,接下来就可以进入正式的 编码阶段了

我们之前说的有两个内容,一个是切分图片,一个是提升亮度

切分图片的话,主要是用到了opencv的Rect来对roi切分,具体思路见下代码:

	std::vector<cv::Mat> splitImage(const cv::Mat& inputImage, int rows, int cols) {
		std::vector<cv::Mat> subImages;

		int subImageWidth = inputImage.cols / cols;
		int subImageHeight = inputImage.rows / rows;

		for (int y = 0; y < rows; ++y) {
			for (int x = 0; x < cols; ++x) {
				// 定义矩形区域,切分图像
				cv::Rect roi(x * subImageWidth, y * subImageHeight, subImageWidth, subImageHeight);

				// 获取子图像
				cv::Mat subImage = inputImage(roi).clone();

				// 添加到结果集
				subImages.push_back(subImage);
			}
		}

		return subImages;
	}
	cv::Mat enhanceBrightnessImage(const cv::Mat& image) {
		// 转换为YUV颜色空间
		cv::Mat imgYUV;
		cv::cvtColor(image, imgYUV, cv::COLOR_BGR2YUV);

		// 应用CLAHE到Y通道(YUV中的Y代表亮度)
		cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(2.0, cv::Size(8, 8));
		clahe->apply(0, imgYUV);  // 修正此行代码

		// 将结果转换回BGR格式
		cv::Mat imgOutput;
		cv::cvtColor(imgYUV, imgOutput, cv::COLOR_YUV2BGR);

		return imgOutput;
	}

项目整体代码如下:
头文件Lev_PictureManager.h

// Lev_PictureManager.h: 标准系统包含文件的包含文件
// 或项目特定的包含文件。

#pragma once

#include <iostream>
// TODO: 在此处引用程序需要的其他标头。
#include "filesystem"
#include "opencv2/opencv.hpp"

namespace Lev_PictureManager {
	/// <summary>
	/// 判断文件后缀是否为支持的图片
	/// </summary>
	/// <param name="extension">传入后缀,支持输入.jpg .png .jpeg</param>
	/// <returns>是否支持</returns>
	bool isImageFileExtend(const std::string extension);
	/// <summary>
	/// 缩放图片大小到指定大小
	/// </summary>
	/// <param name="insertPath">输入图片的绝对路径,包括图片名称</param>
	/// <param name="outputPath">输出图片的绝对路径,包括图片名称</param>
	/// <param name="tar_width">目标缩放宽度</param>
	/// <param name="tar_height">目标缩放高度</param>
	/// <returns>成功与否</returns>
	bool ResizeSingleImage(const std::string& insert_picture, const std::string& output_path, int tar_width, int tar_height);
	
	/// <summary>
	/// 将指定图片路径输入,导到指定目录中去
	/// </summary>
	/// <param name="insert_picture">输入图片路径</param>
	/// <param name="output_path">输出分裂图片的路径</param>
	/// <param name="row">指定切分行数</param>
	/// <param name="col">指定切分列数</param>
	/// <param name="suffix">后缀,默认是_,不同的图片会在指定后缀后,加上row-col的后缀比如 test_1-12.jpeg</param>
	/// <returns>是否切分成功</returns>
	bool TearPicture(const std::string& insert_picture, const std::string& output_path, int row, int col,const std::string& suffix);

	/// <summary>
	/// 调整图片亮度到最佳
	/// </summary>
	/// <param name="input_picture">输入图片的路径</param>
	/// <param name="output_path">图片输出路径</param>
	/// <returns></returns>
	bool adjustBrightness(const std::string& input_picture, const std::string& output_path);

}

Lev_PictureManager.cpp

// Lev_PictureManager.cpp: 定义应用程序的入口点。
//


#include "Lev_PictureManager.h"
using namespace std;
namespace fs = std::filesystem;
//使用命名空间是一种美德:D
namespace Lev_PictureManager {
	bool isImageFileExtend(const std::string extension){
		// 在这里添加你需要支持的图片格式的判断条件
		return extension == ".jpg" || extension == ".png" || extension == ".jpeg";
	}

	bool ResizeSingleImage(const std::string& insertPath, const std::string& outputPath, int tar_width, int tar_height) {
		cv::Mat originalImage = cv::imread(cv::String(insertPath), cv::IMREAD_COLOR);
		cv::String outString = cv::String(outputPath);
		if (originalImage.empty()) {
			std::cerr << "Failed to open image!" << std::endl;
			return false;
		}

		// 获取原始图像的宽高
		int originalWidth = originalImage.cols;
		int originalHeight = originalImage.rows;

		// 计算缩放比例
		double scaleWidth = static_cast<double>(tar_width) / originalWidth;
		double scaleHeight = static_cast<double>(tar_height) / originalHeight;

		// 使用 resize 函数进行缩放
		cv::Mat resizedImage;
		cv::resize(originalImage, resizedImage, cv::Size(), scaleWidth, scaleHeight, cv::INTER_LINEAR);

		// 保存压缩后的图像
		if (!cv::imwrite(outString, resizedImage)) return false;
		return true;
	}


	
	std::vector<cv::Mat> splitImage(const cv::Mat& inputImage, int rows, int cols) {
		std::vector<cv::Mat> subImages;

		int subImageWidth = inputImage.cols / cols;
		int subImageHeight = inputImage.rows / rows;

		for (int y = 0; y < rows; ++y) {
			for (int x = 0; x < cols; ++x) {
				// 定义矩形区域,切分图像
				cv::Rect roi(x * subImageWidth, y * subImageHeight, subImageWidth, subImageHeight);

				// 获取子图像
				cv::Mat subImage = inputImage(roi).clone();

				// 添加到结果集
				subImages.push_back(subImage);
			}
		}

		return subImages;
	}
	bool TearPicture(const std::string& insert_picture, const std::string& output_path, int row, int col, const std::string& suffix)
	{
		//判断输入图片是否是支持的文件
		fs::path insertPath(insert_picture);
		if(!fs::is_regular_file(insertPath)) return false;
		if(!isImageFileExtend(insertPath.extension().string())) return false;

		//不带后缀的后缀名
		std::string insert_picture_name = insertPath.stem().string();

		//将图片切分成vector
		cv::Mat mat_insert = cv::imread(insert_picture);

		std::vector<cv::Mat> vec_ret = splitImage(mat_insert, row, col);

		//将vector中的图片保存到指定路径
		for (int i = 0; i < row; ++i) {
			for (int j = 0; j < col; ++j) {
				std::string output_name = output_path + "/" + insert_picture_name + "_" + std::to_string(i) + "-" + std::to_string(j) + "." + suffix;
				if (!cv::imwrite(output_name, vec_ret[i + j])) return false;
			}
		}

		return true;
	}

	cv::Mat enhanceBrightnessImage(const cv::Mat& image) {
		// 转换为YUV颜色空间
		cv::Mat imgYUV;
		cv::cvtColor(image, imgYUV, cv::COLOR_BGR2YUV);

		// 应用CLAHE到Y通道(YUV中的Y代表亮度)
		cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(2.0, cv::Size(8, 8));
		clahe->apply(0, imgYUV);  // 修正此行代码

		// 将结果转换回BGR格式
		cv::Mat imgOutput;
		cv::cvtColor(imgYUV, imgOutput, cv::COLOR_YUV2BGR);

		return imgOutput;
	}

	bool adjustBrightness(const std::string& input_picture, const std::string& output_path)
	{
		//判断输入图片是否是支持的文件
		fs::path insertPath(input_picture);
		if (!fs::is_regular_file(insertPath)) return false;
		if (!isImageFileExtend(insertPath.extension().string())) return false;

		std::string input_filename = insertPath.filename().string();
		std::string output_filename = output_path + "/" + input_filename;
		cv::Mat mat_input = cv::imread(input_picture);
		cv::Mat mat_output = enhanceBrightnessImage(mat_input);

		if (!cv::imwrite(output_filename, mat_output)) return false;
		return true;
	}


	
}

完整工程(带Demo)见本人Github:

LeventureQys/Lev_PictureManager


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK