Mat图像中文字断笔画处理
在C++中处理Mat灰度图像上的文字时,当细小笔画的文字在二值化后,有些只有1-2像素的文字笔画就会断开,如果在threshold函数的阈值设置低一些的话,渐变灰度又变成了大块白色或者黑色,如何只提取1-2像素笔画的文字进行处理,这些文字包括不同字体的中文、英文、数字以及符号以及1-2像素的线条 在处理Mat灰度图像时,为了有效提取和处理1-2像素宽的文字和线条,你可以考虑以下步骤:1. **自适应二值化**:使用自适应阈值(如 `adaptiveThreshold`)替代固定阈值的 `threshold` 函数。这样可以在不同的图像区域使用不同的阈值,适应细小笔画。
cv::adaptiveThreshold(src, dst, maxValue, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, blockSize, C);
- `maxValue`:二值化后非零像素的值。
- `blockSize`:用于计算阈值的邻居像素的大小。
- `C`:从均值或加权均值中减去常量C。
2. **细化算法**:应用细化(骨架化)算法,使得线条更加纤细,便于连接断开的笔画。
cv::ximgproc::thinning(src, dst, cv::ximgproc::THINNING_ZHANGSUEN);
3. **形态学操作**:使用形态学操作如腐蚀(`erode`)和膨胀(`dilate`)来连接断开的笔画。这可以帮助填补细小的断口,但记得要小心调整内核大小。
cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2,2));
cv::morphologyEx(src, dst, cv::MORPH_CLOSE, element);
4. **边缘检测**:使用 Canny 边缘检测来强调图像中所有的边缘,之后再使用形态学操作来连接断开的细小笔画。
cv::Canny(src, edges, threshold1, threshold2);
这些步骤可以帮助你更好地提取和处理细小笔画的文字。请根据图像的具体特征和降噪要求进行参数调整。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-12-12 11:05
在处理Mat灰度图像时,为了有效提取和处理1-2像素宽的文字和线条,你可以考虑以下步骤:
1. **自适应二 ...
这4步是组合起来使用还是单独用一个就可以实现笔画不断开?请写一个详细的例子 cxnet 发表于 2024-12-12 11:26
这4步是组合起来使用还是单独用一个就可以实现笔画不 ...
为了处理细小笔画不断开的问题,通常需要结合多个步骤,具体可以根据效果逐步调整。下面是一个完整的例子,展示如何处理细小笔画的断开问题:
#include <opencv2/opencv.hpp>
#include <opencv2/ximgproc.hpp>
int main() {
// 载入灰度图像
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
if (src.empty()) {
std::cerr << "图像加载失败!" << std::endl;
return -1;
}
cv::Mat binarized, thinned, edges, result;
// 1. 自适应二值化
cv::adaptiveThreshold(src, binarized, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 15, 5);
// 2. 细化(骨架化)算法
cv::ximgproc::thinning(binarized, thinned, cv::ximgproc::THINNING_ZHANGSUEN);
// 3. Canny边缘检测
cv::Canny(thinned, edges, 50, 150);
// 4. 形态学操作封闭小空隙
cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2, 2));
cv::morphologyEx(edges, result, cv::MORPH_CLOSE, element);
// 显示结果
cv::imshow("源图像", src);
cv::imshow("处理后的图像", result);
cv::waitKey(0);
return 0;
}
### 说明:
1. **自适应二值化**:用于将图像转换为二值图像,这一步能处理光照不均的问题。
2. **细化(骨架化)**:使细小笔画更细,可能会消除一些小的断线。
3. **边缘检测**:强调边缘,找出所有可能的笔画连接。
4. **形态学操作**:使用闭运算连接断开的笔画。
可以根据实际的需求和效果调节自适应二值化的参数、Canny边缘检测的阈值、以及形态学运算的内核大小。当效果看起来比较理想时,表示这些步骤已经足够;否则,你可以视需要去掉或调整某个步骤。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 在C++中,一张灰度Mat图像上面有纯黑色和纯白色文字和线条以及各种白色和黑色图案,以及灰色图案,是否可以只查找白色线条文字的边缘,文字包括各种字体的中文、英文、符号,将找到的轮廓内部填充为168的灰色,黑色文字图案线条内容以及灰色内容保持不变 cxnet 发表于 2024-12-12 15:30
在C++中,一张灰度Mat图像上面有纯黑色和纯白色文字和 ...
要在灰度Mat图像中查找并填充白色线条文字的边缘,同时保持黑色和灰色图案不变,可以使用OpenCV进行以下处理:
1. **二值化**:首先将图像二值化,只保留白色文字和线条。
2. **查找轮廓**:找到白色区域的轮廓。
3. **填充轮廓**:将找到的轮廓填充为灰色值(168)。
以下是一个示例代码:
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
// 载入灰度图像
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
if (src.empty()) {
std::cerr << "图像加载失败!" << std::endl;
return -1;
}
// 二值化,只保留较亮的部分
cv::Mat binary;
cv::threshold(src, binary, 200, 255, cv::THRESH_BINARY);
// 查找轮廓
std::vector<std::vector<cv::Point>> contours;
cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// 创建一个新的图像用于填充
cv::Mat result = src.clone();
// 填充轮廓,颜色为168的灰色
for (size_t i = 0; i < contours.size(); ++i) {
cv::drawContours(result, contours, static_cast<int>(i), cv::Scalar(168), cv::FILLED);
}
// 显示结果
cv::imshow("Result", result);
cv::waitKey(0);
return 0;
}
### 关键点解释:
- **cv::threshold**:用于二值化图像,这里选择阈值200是为了尽可能只保留白色文字和线条。
- **cv::findContours**:用于查找二值图像中的轮廓。
- **cv::drawContours**:用于将找到的轮廓填充为灰色(168),这样可以保留图像中非白色的部分原样。
通过这段代码,可以实现仅处理白色文字和线条的效果,其余黑色和灰色内容将保持不变。根据你的图像特性,你可能需要调整二值化的阈值以更好地分离白色文本。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-12-12 15:30
要在灰度Mat图像中查找并填充白色线条文字的边缘,同时保持黑色和灰色图案不变,可以使用OpenCV进行以 ...
我的意思是查找白色文字线条的外部轮廓线以此形成封闭区域,然后将封闭的区域重新填成168灰度,原图的黑色和灰色保持不变,而此段代码处理完后整个图都成了168灰色了 cxnet 发表于 2024-12-12 15:38
我的意思是查找白色文字线条的外部轮廓线以此形成封闭 ...
了解了你的需求后,以下是一种实现你描述效果的方法:仅查找白色文字线条的外部轮廓,然后将这些封闭区域填充为灰色(168),同时保持黑色和灰色区域不变。
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
// 读取灰度图像
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
if (src.empty()) {
std::cerr << "无法打开图像文件!" << std::endl;
return -1;
}
// 复制原始图像以保存处理结果
cv::Mat result = src.clone();
// 二值化(可以根据需要调整阈值)
cv::Mat binary;
cv::threshold(src, binary, 200, 255, cv::THRESH_BINARY);
// 查找轮廓
std::vector<std::vector<cv::Point>> contours;
cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// 填充找到的轮廓
for (size_t i = 0; i < contours.size(); ++i) {
cv::drawContours(result, contours, static_cast<int>(i), cv::Scalar(168), cv::FILLED);
}
// 显示结果图像
cv::imshow("Result", result);
cv::waitKey(0);
return 0;
}
**注意事项:**
- 使用 `cv::threshold` 来进行二值化,选择合适的阈值确保只选中白色文字。
- 使用 `cv::findContours` 来查找外部轮廓。
- 使用 `cv::drawContours` 中的 `cv::Scalar(168)` 来填充轮廓为灰色。
- 请根据你的图像具体情况调整二值化的阈值以确保只选中白色部分。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 C++中,有不同大小的白色和黑色文字,如果只想提取轮廓高度小于70像素且颜色为白色的文字到新的Mat图像中应该怎么写代码? cxnet 发表于 2024-12-13 10:05
C++中,有不同大小的白色和黑色文字,如果只想提取轮 ...
为了在C++中提取高度小于70像素且为白色的文字,并将其存储到新的Mat图像中,你可以按照以下步骤进行操作:
1. 将图像转换为二值图像,以便更容易检测白色文字。
2. 查找图像中的所有轮廓。
3. 筛选出高度小于70像素的白色文字轮廓。
4. 将这些轮廓复制到新的Mat图像中。
下面是一个简单的示例代码:
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
// 读取灰度图像
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
if (src.empty()) {
std::cerr << "无法加载图像" << std::endl;
return -1;
}
// 转换为二值图像
cv::Mat binary;
cv::threshold(src, binary, 200, 255, cv::THRESH_BINARY); // 200是阈值,调整以适应您的图像
// 查找轮廓
std::vector<std::vector<cv::Point>> contours;
cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// 创建一个新的Mat图像来存储结果
cv::Mat result = cv::Mat::zeros(src.size(), src.type());
for (const auto& contour : contours) {
// 获取轮廓的边界矩形
cv::Rect boundingBox = cv::boundingRect(contour);
// 筛选满足条件的轮廓
if (boundingBox.height < 70) {
// 绘制满足条件的轮廓到result图像中
cv::drawContours(result, std::vector<std::vector<cv::Point>>{contour}, -1, cv::Scalar(255), cv::FILLED);
}
}
// 显示结果
cv::imshow("Result", result);
cv::waitKey(0);
return 0;
}
上述代码通过找出所有的轮廓,并根据高度筛选满足条件的白色文字,将其绘制到新的Mat图像中。你可能需要根据你的图像特性调整二值化的阈值。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-12-13 10:30
为了在C++中提取高度小于70像素且为白色的文字,并将其存储到新的Mat图像中,你可以按照以下步骤进行操 ...
cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
这一句报错 cxnet 发表于 2024-12-13 10:58
cv::findContours(binary, contours, cv::RETR_EXTERN ...
根据您提供的信息,在使用 `cv::findContours` 时,可能是因为传递的参数或环境配置原因导致报错。以下是完整的代码示例,确保在使用时没有遗漏任何步骤:
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
// 读取灰度图像
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
if (src.empty()) {
std::cerr << "无法加载图像!" << std::endl;
return -1;
}
// 二值化图像
cv::Mat binary;
cv::threshold(src, binary, 200, 255, cv::THRESH_BINARY);
// 查找图像中的轮廓
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(binary, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// 创建一个与原始图像大小相同的全黑图像
cv::Mat result = cv::Mat::zeros(src.size(), src.type());
// 遍历每个轮廓
for (size_t i = 0; i < contours.size(); i++) {
// 计算轮廓的边界矩形
cv::Rect boundingBox = cv::boundingRect(contours);
// 检查轮廓高度并在 0 和 255 的范围内过滤白色
if (boundingBox.height < 70) {
// 提取并填充到新的图像中
cv::drawContours(result, contours, static_cast<int>(i), cv::Scalar(255), cv::FILLED);
}
}
// 显示结果
cv::imshow("Result", result);
cv::waitKey(0);
return 0;
}
请确保以下几点:
1. 已经正确引入OpenCV库。
2. 输入图像路径正确。
3. `cv::imread` 读取成功。
4. 环境中配置了正确版本的OpenCV。
如果使用 CMake,确保 `find_package(OpenCV REQUIRED)` 配置正确,并将 `target_link_libraries` 适配到项目中。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-12-13 10:30
为了在C++中提取高度小于70像素且为白色的文字,并将其存储到新的Mat图像中,你可以按照以下步骤进行操 ...
最终输出的是一张全黑的图像,没有任何文字或者轮廓 cxnet 发表于 2024-12-13 11:09
最终输出的是一张全黑的图像,没有任何文字或者轮廓
抱歉给您带来困扰。我们可以按步骤重新检查代码,并纠正可能导致输出全黑图像的问题。通常,这种情况可能是由于没有正确提取到符合条件的轮廓或者图像复制的问题。以下是一个完整的示例代码,展示如何提取符合条件的白色文字轮廓:
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
// 读取灰度图像
cv::Mat src = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
if (src.empty()) {
std::cerr << "Could not open the image file." << std::endl;
return -1;
}
// 将图像二值化
cv::Mat binary;
cv::threshold(src, binary, 200, 255, cv::THRESH_BINARY); // 假设白色文字接近255
// 查找轮廓
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(binary, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// 创建空白图像用于存放符合条件的文字
cv::Mat result = cv::Mat::zeros(src.size(), CV_8UC1);
// 遍历所有轮廓
for (size_t i = 0; i < contours.size(); ++i) {
// 获取轮廓的边界矩形
cv::Rect boundingBox = cv::boundingRect(contours);
// 检查轮廓的高度是否小于70像素
if (boundingBox.height < 70) {
// 在结果图像上绘制符合条件的轮廓
cv::drawContours(result, contours, static_cast<int>(i), cv::Scalar(255), cv::FILLED);
}
}
// 显示结果
cv::imshow("Extracted Contours", result);
cv::waitKey(0);
return 0;
}
这个代码中,我们对每一个轮廓的边界矩形进行检查,以确保高度小于70像素,然后在结果图像中绘制这些轮廓。请确保:
- 输入图像确实包含比200亮度更高的白色文字部分(可以调整 `cv::threshold` 的阈值来适应不同的图像)。
- 使用 `cv::imshow` 可以在窗口中正确显示结果图像, `cv::waitKey(0)` 确保窗口不会立刻关闭。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页:
[1]