From 6cc26faeab2de4bd68f52455af035fce77a779dd Mon Sep 17 00:00:00 2001 From: zjc-zjc-123 <1714105370@qq.com> Date: Mon, 11 Nov 2024 17:57:08 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=81=E7=A7=BB=E9=A1=B9=E7=9B=AE=E5=88=B0CL?= =?UTF-8?q?ion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- CMakeLists.txt | 26 +++++++ README.md | 13 +++- cotton_color.cpp | 146 +++++++++++++++++++++++----------------- cotton_color.vcxproj | 7 +- cotton_color2.cpp | 157 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 286 insertions(+), 67 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 cotton_color2.cpp diff --git a/.gitignore b/.gitignore index 9491a2f..621be39 100644 --- a/.gitignore +++ b/.gitignore @@ -360,4 +360,6 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd + +.idea \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b60ffde --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.29) +project(cotton_color) + + +set(CMAKE_CXX_STANDARD 17) + +# 设置 OpenCV 路径 +set(OpenCV_DIR "E:/opencv4.10/opencv/build") + +# 找到 OpenCV 包 +find_package(OpenCV REQUIRED) + +add_definitions(-DUNICODE -D_UNICODE) +# 包含头文件路径 +include_directories(${OpenCV_INCLUDE_DIRS}) + +# 添加可执行文件 +add_executable(cotton_color cotton_color.cpp) +# 链接 OpenCV 库 +target_link_libraries(cotton_color ${OpenCV_LIBS} comdlg32) + + +# 添加可执行文件 +add_executable(cotton_color2 cotton_color2.cpp) +# 链接 OpenCV 库 +target_link_libraries(cotton_color2 ${OpenCV_LIBS} comdlg32) \ No newline at end of file diff --git a/README.md b/README.md index 29c2b25..8053519 100644 --- a/README.md +++ b/README.md @@ -49,5 +49,14 @@ L a* b* 色彩空间检测,检测明黄色、白色。 激进方案 -> 深度学习 - > 区块判别 -> 杂质 | | 保守方案 -> 深度学习确认 -> 杂质 - - \ No newline at end of file + +讨论记录: + +暗红色(棉叶) + +棉花亮度低 + +黑线、黑色孔洞 + +土黄 + diff --git a/cotton_color.cpp b/cotton_color.cpp index 877fc36..f8624bb 100644 --- a/cotton_color.cpp +++ b/cotton_color.cpp @@ -1,135 +1,157 @@ -#include +#include #include #include #include #include -#include // 包含文件对话框相关的函数 - +#include // ļԻصĺ using namespace cv; using namespace std; - /** - * @brief 鲜艳色彩检测函数,通过饱和度阈值检测输入图像中鲜艳的颜色区域。 + * @brief ɫʼ⺯ͨͶֵͼ޵ɫ * - * 此函数将输入图像从 BGR 色彩空间转换到 HSV 色彩空间,并提取出饱和度 (S) 通道。然后,通过设置饱和度阈值, - * 来检测图像中饱和度大于阈值的区域,标记为输出图像的鲜艳颜色区域。 - * - * @param inputImage 输入图像,类型为 cv::Mat,要求为 BGR 色彩空间。 - * @param outputImage 输出图像,类型为 cv::Mat,输出图像将标记出鲜艳颜色区域,原始图像尺寸。 - * @param saturationThreshold 饱和度阈值,类型为 int,用于过滤低饱和度的区域,范围通常为 0 到 255。 - * 饱和度高于此阈值的区域将被认为是鲜艳的颜色。 - * - * @note 饱和度阈值越高,输出图像将只保留更为鲜艳的区域。 - * 若饱和度阈值过低,可能会检测到过多的区域。 + * @param inputImage ͼΪ cv::MatҪΪ BGR ɫʿռ䡣 + * @param outputImage ͼΪ cv::Matͼ񽫱dzɫԭʼͼߴ硣 + * @param params ӳ䣬ڴݸֿõIJ籥Ͷֵȡ */ - /** - * @brief 鲜艳色彩检测函数,通过饱和度阈值检测输入图像中鲜艳的颜色区域。 - * - * @param inputImage 输入图像,类型为 cv::Mat,要求为 BGR 色彩空间。 - * @param outputImage 输出图像,类型为 cv::Mat,输出图像将标记出鲜艳颜色区域,原始图像尺寸。 - * @param params 参数映射,用于传递各种可配置的参数,如饱和度阈值等。 - */ void vibrantColorDetection(const Mat& inputImage, Mat& outputImage, const map& params) { - // 从参数映射中获取饱和度阈值 + // ӲӳлȡͶֵ int saturationThreshold = params.at("saturationThreshold"); - // 将输入图像从 BGR 转换为 HSV + // ͼ BGR תΪ HSV Mat hsvImage; cvtColor(inputImage, hsvImage, COLOR_BGR2HSV); - // 分离 HSV 图像的各个通道 + // HSV ͼĸͨ Mat channels[3]; split(hsvImage, channels); - // 获取饱和度通道 (S) + // ȡͶͨ (S) Mat saturation = channels[1]; - // 创建输出图像,将饱和度大于阈值的区域标记为杂质 + // ͼ񣬽ͶȴֵΪ outputImage = Mat::zeros(inputImage.size(), CV_8UC1); - // 对饱和度图像应用阈值处理 + // ԱͶͼӦֵ threshold(saturation, outputImage, saturationThreshold, 255, THRESH_BINARY); } +/** + * @brief ļԻ򣬷ѡļ· + * + * @return ѡļ·Ϊ std::wstringûȡѡ񣬷ؿַ + */ +std::wstring openFileDialog() { + // ʼļѡԻ + OPENFILENAMEW ofn; // ʹÿַ汾Ľṹ + wchar_t szFile[260] = {0}; // 洢ѡļ· -string openFileDialog() { - // 初始化文件选择对话框 - OPENFILENAME ofn; // 文件对话框结构 - wchar_t szFile[260]; // 存储选择的文件路径 - - // 设置 OPENFILENAME 结构的默认值 + // OPENFILENAMEW ṹĬֵ ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = NULL; - ofn.lpstrFile = szFile; + ofn.lpstrFile = szFile; // ļ· ofn.nMaxFile = sizeof(szFile) / sizeof(szFile[0]); ofn.lpstrFilter = L"Image Files\0*.BMP;*.JPG;*.JPEG;*.PNG;*.GIF\0All Files\0*.*\0"; ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; + ofn.lpstrFileTitle = NULL; // Ҫļ ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; - ofn.lpstrTitle = L"Select an image file"; + ofn.lpstrInitialDir = NULL; // ʹĬϳʼĿ¼ + ofn.lpstrTitle = L"Select an image file"; // Ի ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - // 打开文件选择对话框 - if (GetOpenFileName(&ofn) == TRUE) { - // 将 wchar_t 转换为 string - wstring ws(szFile); - string filePath(ws.begin(), ws.end()); - return filePath; + // ļѡԻ + if (GetOpenFileNameW(&ofn) == TRUE) { + return szFile; // ѡеļ· } - return ""; // 如果用户取消,返回空字符串 + return L""; // ûȡؿַ } - +/** + * @brief ȡͼļ֧ Unicode · + * + * @return صͼΪ cv::Matʧܣؿյ Mat + */ Mat readImage() { - // 读取输入图像 - string imagePath = openFileDialog(); + // ȡͼ· + std::wstring imagePath = openFileDialog(); if (imagePath.empty()) { - cout << "No file selected or user cancelled." << endl; + wcout << L"No file selected or user cancelled." << endl; return Mat(); } - // 使用 OpenCV 读取选中的图片 - Mat image = imread(imagePath); + // ʹ Windows API ļ + HANDLE hFile = CreateFileW(imagePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + wcout << L"Error: Could not open file." << endl; + return Mat(); + } + + // ȡļС + LARGE_INTEGER fileSize; + if (!GetFileSizeEx(hFile, &fileSize)) { + wcout << L"Error: Could not get file size." << endl; + CloseHandle(hFile); + return Mat(); + } + + if (fileSize.QuadPart > MAXDWORD) { + wcout << L"Error: File size too large." << endl; + CloseHandle(hFile); + return Mat(); + } + + DWORD dwFileSize = static_cast(fileSize.QuadPart); + + // ȡļݵ + std::vector buffer(dwFileSize); + DWORD bytesRead = 0; + if (!ReadFile(hFile, buffer.data(), dwFileSize, &bytesRead, NULL) || bytesRead != dwFileSize) { + wcout << L"Error: Could not read file." << endl; + CloseHandle(hFile); + return Mat(); + } + + CloseHandle(hFile); + + // ʹ OpenCV ڴ滺ȡͼ + Mat image = imdecode(buffer, IMREAD_COLOR); if (image.empty()) { - cout << "Error: Could not load image." << endl; + wcout << L"Error: Could not decode image." << endl; return Mat(); } return image; } - int main() { - // 读取输入图像 - Mat inputImage = readImage(); + // ȡͼ + Mat inputImage = readImage(); if (inputImage.empty()) { cout << "Error: Could not load image." << endl; return -1; } - // 创建输出图像 + // ͼ Mat outputImage; - // 使用 map 模拟 JSON 参数传递 + // ʹ map ģ map params; - params["saturationThreshold"] = 100; // 设置饱和度阈值为100 + params["saturationThreshold"] = 100; // ñͶֵΪ 100 - // 调用鲜艳颜色检测函数 + // ɫ⺯ vibrantColorDetection(inputImage, outputImage, params); - // 显示原图和检测到的鲜艳区域 + // ʾԭͼͼ⵽ imshow("Original Image", inputImage); imshow("Detected Vibrant Colors", outputImage); - // 等待用户按键 + // ȴû waitKey(0); return 0; -} \ No newline at end of file +} diff --git a/cotton_color.vcxproj b/cotton_color.vcxproj index fd94705..713fece 100644 --- a/cotton_color.vcxproj +++ b/cotton_color.vcxproj @@ -104,10 +104,13 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true + $(mil_path64)\..\include;%(AdditionalIncludeDirectories) Console true + $(mil_path64)\..\lib\ + mil.lib;Mil3d.lib;milim.lib;miledge.lib;%(AdditionalDependencies) @@ -118,14 +121,14 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - C:\Users\ZLSDKJ\source\opencv\build\include;%(AdditionalIncludeDirectories) + C:\Users\zjc\source\opencv\build\include;%(AdditionalIncludeDirectories) Console true true true - C:\Users\ZLSDKJ\source\opencv\build\x64\vc16\lib;%(AdditionalLibraryDirectories) + C:\Users\zjc\source\opencv\build\x64\vc16\lib;%(AdditionalLibraryDirectories) Comdlg32.lib;opencv_world4100.lib;%(AdditionalDependencies) diff --git a/cotton_color2.cpp b/cotton_color2.cpp new file mode 100644 index 0000000..c6ab671 --- /dev/null +++ b/cotton_color2.cpp @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include +#include // 包含文件对话框相关的函数 + +using namespace cv; +using namespace std; + +/** + * @brief 鲜艳色彩检测函数,通过饱和度阈值检测输入图像中鲜艳的颜色区域。 + * + * @param inputImage 输入图像,类型为 cv::Mat,要求为 BGR 色彩空间。 + * @param outputImage 输出图像,类型为 cv::Mat,输出图像将标记出鲜艳颜色区域,原始图像尺寸。 + * @param params 参数映射,用于传递各种可配置的参数,如饱和度阈值等。 + */ +void vibrantColorDetection(const Mat& inputImage, Mat& outputImage, const map& params) { + // 从参数映射中获取饱和度阈值 + int saturationThreshold = params.at("saturationThreshold"); + + // 将输入图像从 BGR 转换为 HSV + Mat hsvImage; + cvtColor(inputImage, hsvImage, COLOR_BGR2HSV); + + // 分离 HSV 图像的各个通道 + Mat channels[3]; + split(hsvImage, channels); + + // 获取饱和度通道 (S) + Mat saturation = channels[1]; + + // 创建输出图像,将饱和度大于阈值的区域标记为杂质 + outputImage = Mat::zeros(inputImage.size(), CV_8UC1); + + // 对饱和度图像应用阈值处理 + threshold(saturation, outputImage, saturationThreshold, 255, THRESH_BINARY); +} + +/** + * @brief 打开文件对话框,返回选中文件的路径。 + * + * @return 选中文件的完整路径,类型为 std::wstring。如果用户取消选择,返回空字符串。 + */ +std::wstring openFileDialog() { + // 初始化文件选择对话框 + OPENFILENAMEW ofn; // 使用宽字符版本的结构 + wchar_t szFile[260] = {0}; // 存储选择的文件路径 + + // 设置 OPENFILENAMEW 结构的默认值 + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = NULL; + ofn.lpstrFile = szFile; // 设置文件路径缓冲区 + ofn.nMaxFile = sizeof(szFile) / sizeof(szFile[0]); + ofn.lpstrFilter = L"Image Files\0*.BMP;*.JPG;*.JPEG;*.PNG;*.GIF\0All Files\0*.*\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; // 不需要单独的文件名 + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; // 使用默认初始目录 + ofn.lpstrTitle = L"Select an image file"; // 对话框标题 + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + // 打开文件选择对话框 + if (GetOpenFileNameW(&ofn) == TRUE) { + return szFile; // 返回选中的文件路径 + } + + return L""; // 如果用户取消,返回空字符串 +} + +/** + * @brief 读取图像文件,支持 Unicode 路径。 + * + * @return 加载的图像,类型为 cv::Mat。如果加载失败,返回空的 Mat。 + */ +Mat readImage() { + // 读取输入图像路径 + std::wstring imagePath = openFileDialog(); + + if (imagePath.empty()) { + wcout << L"No file selected or user cancelled." << endl; + return Mat(); + } + + // 使用 Windows API 打开文件 + HANDLE hFile = CreateFileW(imagePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + wcout << L"Error: Could not open file." << endl; + return Mat(); + } + + // 获取文件大小 + LARGE_INTEGER fileSize; + if (!GetFileSizeEx(hFile, &fileSize)) { + wcout << L"Error: Could not get file size." << endl; + CloseHandle(hFile); + return Mat(); + } + + if (fileSize.QuadPart > MAXDWORD) { + wcout << L"Error: File size too large." << endl; + CloseHandle(hFile); + return Mat(); + } + + DWORD dwFileSize = static_cast(fileSize.QuadPart); + + // 读取文件内容到缓冲区 + std::vector buffer(dwFileSize); + DWORD bytesRead = 0; + if (!ReadFile(hFile, buffer.data(), dwFileSize, &bytesRead, NULL) || bytesRead != dwFileSize) { + wcout << L"Error: Could not read file." << endl; + CloseHandle(hFile); + return Mat(); + } + + CloseHandle(hFile); + + // 使用 OpenCV 从内存缓冲区读取图像 + Mat image = imdecode(buffer, IMREAD_COLOR); + + if (image.empty()) { + wcout << L"Error: Could not decode image." << endl; + return Mat(); + } + + return image; +} + +int main() { + // 读取输入图像 + Mat inputImage = readImage(); + + if (inputImage.empty()) { + cout << "Error: Could not load image." << endl; + return -1; + } + + // 创建输出图像 + Mat outputImage; + + // 使用 map 模拟参数传递 + map params; + params["saturationThreshold"] = 100; // 设置饱和度阈值为 100 + + // 调用鲜艳颜色检测函数 + vibrantColorDetection(inputImage, outputImage, params); + + // 显示原图和检测到的鲜艳区域 + imshow("Original Image", inputImage); + imshow("Detected Vibrant Colors", outputImage); + + // 等待用户按键 + waitKey(0); + return 0; +}