|
|
您指出的问题非常关键。让我提供一个修正版本,解决角度分割问题和纯色处理问题:
- #include <opencv2/opencv.hpp>
- #include <vector>
- #include <cmath>
- using namespace cv;
- using namespace std;
- const int N = 8;
- const float PI = 3.14159265358979323846f;
- // 修正的阈值矩阵
- int circularDotMatrix[N][N] = {
- { 32, 8, 16, 40, 48, 24, 56, 64 },
- { 4, 0, 12, 36, 44, 20, 52, 60 },
- { 24, 8, 20, 44, 52, 28, 60, 68 },
- { 12, 0, 16, 40, 48, 20, 56, 64 },
- { 40, 16, 28, 52, 60, 36, 68, 76 },
- { 20, 4, 24, 48, 56, 28, 64, 72 },
- { 56, 32, 44, 68, 76, 52, 84, 92 },
- { 36, 16, 40, 64, 72, 44, 80, 88 }
- };
- // 检查是否为纯色文字边缘
- bool isSolidTextEdge(const vector<Mat>& cmykChannels, int x, int y) {
- // 检查所有通道,如果任何一个通道是纯色且当前像素是边缘灰色
- for (int c = 0; c < 4; c++) {
- uchar pixelValue = cmykChannels[c].at<uchar>(y, x);
-
- // 如果是纯色(0或255),直接返回false
- if (pixelValue == 0 || pixelValue == 255) {
- return false;
- }
-
- // 检查周围2像素内是否有纯色像素
- for (int dy = -2; dy <= 2; dy++) {
- for (int dx = -2; dx <= 2; dx++) {
- int nx = x + dx;
- int ny = y + dy;
-
- if (nx >= 0 && nx < cmykChannels[c].cols &&
- ny >= 0 && ny < cmykChannels[c].rows) {
- uchar neighborValue = cmykChannels[c].at<uchar>(ny, nx);
- // 如果邻居是纯色,当前像素是边缘
- if (neighborValue == 0 || neighborValue == 255) {
- return true;
- }
- }
- }
- }
- }
- return false;
- }
- // 修正的半色调通道处理 - 解决角度分割问题
- void halftoneChannel(Mat& input, Mat& output, float angle) {
- int width = input.cols;
- int height = input.rows;
-
- float cos_angle = cos(angle);
- float sin_angle = sin(angle);
-
- // 网点间距
- float dotSpacing = 12.0f;
-
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- uchar pixelValue = input.at<uchar>(y, x);
-
- // 如果是纯色(0或255),直接复制
- if (pixelValue == 0 || pixelValue == 255) {
- output.at<uchar>(y, x) = pixelValue;
- continue;
- }
-
- // 计算在旋转网格中的位置 - 修正坐标变换
- float u = (x * cos_angle - y * sin_angle) + width; // 加上偏移避免负值
- float v = (x * sin_angle + y * cos_angle) + height;
-
- // 计算网格单元内的相对位置
- int gridX = static_cast<int>(fmod(u, dotSpacing) / dotSpacing * N);
- int gridY = static_cast<int>(fmod(v, dotSpacing) / dotSpacing * N);
-
- gridX = max(0, min(N-1, gridX));
- gridY = max(0, min(N-1, gridY));
-
- // 获取阈值
- int threshold = circularDotMatrix[gridY][gridX];
-
- // 应用阈值
- if (pixelValue < threshold) {
- output.at<uchar>(y, x) = 0; // 黑色网点
- } else {
- output.at<uchar>(y, x) = 255; // 白色背景
- }
- }
- }
- }
- // 主转换函数
- void convertToHalftone(vector<Mat>& cmykChannels, vector<Mat>& outputChannels) {
- // 定义角度:C-15°, M-75°, Y-0°, K-45°
- float angles[4] = {
- 15.0f * PI / 180.0f,
- 75.0f * PI / 180.0f,
- 0.0f,
- 45.0f * PI / 180.0f
- };
-
- int width = cmykChannels[0].cols;
- int height = cmykChannels[0].rows;
-
- // 创建纯色边缘掩膜
- Mat edgeMask = Mat::zeros(height, width, CV_8UC1);
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- if (isSolidTextEdge(cmykChannels, x, y)) {
- edgeMask.at<uchar>(y, x) = 255;
- }
- }
- }
-
- // 对每个通道应用半色调
- for (int c = 0; c < 4; c++) {
- outputChannels[c] = Mat(height, width, CV_8UC1);
-
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- uchar pixelValue = cmykChannels[c].at<uchar>(y, x);
-
- // 处理纯色和边缘
- if (pixelValue == 0 || pixelValue == 255 || edgeMask.at<uchar>(y, x)) {
- // 纯色或边缘:保持原值或转为纯色
- if (edgeMask.at<uchar>(y, x)) {
- // 边缘区域:根据原值决定转为纯黑或纯白
- outputChannels[c].at<uchar>(y, x) = (pixelValue < 128) ? 0 : 255;
- } else {
- // 纯色区域:保持原值
- outputChannels[c].at<uchar>(y, x) = pixelValue;
- }
- } else {
- // 非纯色非边缘:正常半色调处理
- halftoneChannel(cmykChannels[c], outputChannels[c], angles[c]);
- }
- }
- }
- }
- }
复制代码
主要修正:
1. **角度分割问题**:在坐标变换中增加了宽度和高度的偏移,确保坐标始终为正,避免分割现象。
2. **纯色文字边缘处理**:
- 扩展了边缘检测函数,检查所有CMYK通道
- 纯色(0或255)保持原值不进行网点化
- 边缘2像素内的灰色区域根据明暗转为纯黑或纯白
3. **处理逻辑**:
- 纯色区域:保持原值
- 纯色边缘:转为纯黑或纯白
- 其他区域:正常半色调处理
这样应该能解决您提到的所有问题,生成正确的半色调网点图案。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 |
|