鱼C论坛

 找回密码
 立即注册
查看: 2013|回复: 43

图像转换

[复制链接]
发表于 2024-12-4 09:52:34 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
请帮忙用C++ MFC写一个将Mat图像转为50Lpi的纯圆点的Halftone,并将相邻的4个点的角度设置为45度,灰度按256级进行处理这样渐变才会平滑,纯黑和纯白不转换,圆点不侵蚀白色区域,保持和photoshop里的灰度图像转Bitmap里的Halftone Screen Method一样的效果,如下图效果
ttsa.png
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-12-7 11:34:17 | 显示全部楼层
cxnet 发表于 2024-12-07 11:33
在这段代码的基础上设置上下左右四个半色调网点组成的 ...


要使半色调网点的排列达到特定的角度,比如45度、75度或15度,需要相应调整网点的排列方式。要实现这种效果,可以通过使用旋转后的网格或调整网点的排列间隔来达到所需的效果。这里是一个通过调整网点间距和布置来实现的思路:

  1. #include <opencv2/opencv.hpp>
  2. #include <iostream>

  3. using namespace cv;

  4. // 生成并返回一个旋转的半色调图案
  5. void createHalftonePattern(Mat &pattern, int dotRadius, double angle) {
  6.     int size = dotRadius * 2; // 图案大小必须充足以旋转
  7.     pattern = Mat::zeros(size * 10, size * 10, CV_8UC1); // 创建一个足够大的图案矩阵

  8.     // 用于计算旋转的点中心和旋转矩阵
  9.     Point center(size, size);
  10.     Mat rotationMatrix = getRotationMatrix2D(center, angle, 1);

  11.     Mat tempPattern = Mat::zeros(size, size, CV_8UC1);
  12.     circle(tempPattern, center, dotRadius, Scalar(255), FILLED);

  13.     // 把圆点阵列用于跨越较大区域
  14.     for (int y = 0; y < pattern.rows; y += size) {
  15.         for (int x = 0; x < pattern.cols; x += size) {
  16.             Mat roi = pattern(Rect(x, y, size, size));
  17.             tempPattern.copyTo(roi);
  18.         }
  19.     }
  20.    
  21.     // 对大的图案应用旋转
  22.     warpAffine(pattern, pattern, rotationMatrix, pattern.size());
  23. }

  24. // 应用半色调效果
  25. void applyHalftonePattern(const Mat &src, Mat &dst, int dotRadius, double angle) {
  26.     Mat pattern;
  27.     createHalftonePattern(pattern, dotRadius, angle);

  28.     dst = src.clone();
  29.     for (int y = 0; y < src.rows; y += pattern.rows) {
  30.         for (int x = 0; x < src.cols; x += pattern.cols) {
  31.             Rect roi(x, y, pattern.cols, pattern.rows);

  32.             // 检查是否超过边界
  33.             if (x + pattern.cols > src.cols || y + pattern.rows > src.rows)
  34.                 continue;

  35.             // 从源提取ROI
  36.             Mat srcRoi = src(roi);

  37.             // 创建一个小于128为黑的掩码用于对原始图像进行阈值化处理
  38.             Mat mask;
  39.             threshold(srcRoi, mask, 128, 255, THRESH_BINARY_INV);

  40.             // 复制图案以适应ROI的大小
  41.             Mat fullPattern;
  42.             pattern(Rect(0, 0, mask.cols, mask.rows)).copyTo(fullPattern);

  43.             // 使用bitwise_and提取组件
  44.             Mat dstRoi = dst(roi);
  45.             fullPattern.copyTo(dstRoi, mask);
  46.         }
  47.     }
  48. }

  49. int main() {
  50.     Mat img = imread("your_image_path.jpg", IMREAD_GRAYSCALE);
  51.     if (img.empty()) {
  52.         std::cerr << "Error: Cannot load image\n";
  53.         return -1;
  54.     }

  55.     Mat halftoneImg;
  56.     applyHalftonePattern(img, halftoneImg, 5, 45); // 调整dotRadius和angle以获得不同效果

  57.     imshow("Halftone Image", halftoneImg);
  58.     waitKey(0);

  59.     return 0;
  60. }
复制代码


**关键点:**

1. **dotRadius**: 控制每个半色调网点的大小。
2. **angle**: 控制整个网点图案旋转的角度,以影响四个网点的排列角度而不是单个网点的相对于光轴的旋转。
3. **布局**: 网点在较大的图案网格上被旋转和应用,以此影响网点布局形成网格的角度。

使用这个代码可以尝试设定`angle`为不同角度来观察网点排列的改变。调整`dotRadius`以匹配特定的像素密度根据你的需要。 这个方法准备了一个旋转后的网格用于实现半色调效果并尝试控制网点排列角度。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-12-7 11:33:45 | 显示全部楼层
FishC 发表于 2024-12-6 15:01
要实现这种效果,可以在绘制圆形网点时,先检查网点周围的像素,确保在靠近白色区域的1像素灰色不绘制 ...

在这段代码的基础上设置上下左右四个半色调网点组成的角度为45度或者75度或者15度,切记是四个网点排列的角度并非1个网点旋转角度
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-12-7 11:27:27 | 显示全部楼层
cxnet 发表于 2024-12-07 11:26
bitwise_and(pattern, mask, dstRoi);
这一行代码报 ...


在使用`bitwise_and`函数时,确保`pattern`和`mask`有相同的尺寸和相同的类型(数据类型)。如果其中一个是一个小图案,需要在应用前调整为与目标区域大小(`dstRoi`)相同。

以下是确保`pattern`和`mask`具有相同尺寸和类型的方法,只需要在代码中做一些调整:

1. **创建标准化区域的掩码**:确保你的掩码每次应用时与`pattern`大小和位置对准。

2. **调整模式尺寸**:如果`pattern`尺寸与处理区域不同,考虑使用`resize`或者复制多个模式单位以覆盖整个区域。

以下是如何修复错误的一种方法:

  1. #include <opencv2/opencv.hpp>
  2. using namespace cv;

  3. // Function to create a halftone pattern
  4. void createHalftonePattern(Mat &pattern, int dotSpacing, double angle) {
  5.     int size = dotSpacing * 2; // Ensure pattern can rotate
  6.     pattern = Mat(size, size, CV_8UC1, Scalar(0));

  7.     Point center(size / 2, size / 2);
  8.     Mat rotationMatrix = getRotationMatrix2D(center, angle, 1);

  9.     // Create initial pattern with a circle
  10.     Mat tempPattern = Mat::zeros(size, size, CV_8UC1);
  11.     circle(tempPattern, center, dotSpacing / 2, Scalar(255), FILLED);

  12.     // Apply rotation to the pattern
  13.     warpAffine(tempPattern, pattern, rotationMatrix, pattern.size());
  14. }

  15. // Function to apply the halftone effect
  16. void applyHalftonePattern(const Mat &src, Mat &dst, int dotSpacing, double angle) {
  17.     Mat pattern;
  18.     createHalftonePattern(pattern, dotSpacing, angle);

  19.     dst = src.clone();
  20.     for (int y = 0; y < src.rows; y += dotSpacing) {
  21.         for (int x = 0; x < src.cols; x += dotSpacing) {
  22.             Rect roi(x, y, dotSpacing, dotSpacing);
  23.             if (x + dotSpacing > src.cols || y + dotSpacing > src.rows)
  24.                 continue;

  25.             // Extract the ROI from the source
  26.             Mat srcRoi = src(roi);

  27.             // Create a mask from the ROI
  28.             Mat mask;
  29.             threshold(srcRoi, mask, 128, 255, THRESH_BINARY);

  30.             // Copy the pattern to the same size as the ROI
  31.             Mat fullPattern;
  32.             pattern(Rect(0, 0, mask.cols, mask.rows)).copyTo(fullPattern);

  33.             // Use bitwise_and to extract the components
  34.             Mat dstRoi = dst(roi);
  35.             bitwise_and(fullPattern, mask, dstRoi);
  36.         }
  37.     }
  38. }

  39. int main() {
  40.     Mat img = imread("your_image_path.jpg", IMREAD_GRAYSCALE);
  41.     if (img.empty()) {
  42.         std::cerr << "Error: Cannot load image\n";
  43.         return -1;
  44.     }

  45.     Mat halftoneImg;
  46.     applyHalftonePattern(img, halftoneImg, 10, 45); // Example with dot size 10 and angle 45

  47.     imshow("Halftone Image", halftoneImg);
  48.     waitKey(0);

  49.     return 0;
  50. }
复制代码


**关键点:**
- **ROI和模式对齐**:确保模式(`pattern`)在每个处理区域(`roi`)都是相同的大小。
- **分区和填充**:通过复制并使用正确的索引调整单个图案。
- **适配边界**:如果需要,确保你处理的区域不会超出图像边界。

使用以上修正确保模式在整个应用过程中对齐和适配目标区域的大小。调试过程中可以检查每次处理中的矩阵类型和大小确保兼容。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-12-7 11:26:05 | 显示全部楼层
FishC 发表于 2024-12-7 11:22
To achieve a halftone effect with specific angles for the dot grid, like 15°, 45°, 75°, or 90 ...

bitwise_and(pattern, mask, dstRoi);
这一行代码报错
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-12-7 11:22:09 | 显示全部楼层
cxnet 发表于 2024-12-07 11:21
这段代码处理出来的图片并没有任何半色调网点,我的意 ...


To achieve a halftone effect with specific angles for the dot grid, like 15°, 45°, 75°, or 90°, you need to consider how the grid of dots is laid out across the image. This involves setting a pattern where dots are repeated in a grid that is rotated by the given angle.

Here is a method using OpenCV to create a halftone effect, where the dots are aligned with a specified grid angle. This involves creating a grid based on the specified line per inch (LPI) and using that to modulate the intensity of the zones of the image.

  1. #include <opencv2/opencv.hpp>
  2. #include <iostream>
  3. #include <cmath>

  4. using namespace cv;

  5. // Function to generate a halftone pattern
  6. void createHalftonePattern(Mat &pattern, int dotSpacing, double angle) {
  7.     int size = dotSpacing * 2; // Size of the pattern
  8.     pattern = Mat(size, size, CV_8UC1, Scalar(0));

  9.     // Convert angle to radians
  10.     double rad = angle * CV_PI / 180.0;

  11.     // Calculate rotation transformation matrix
  12.     Point center(size / 2, size / 2);
  13.     Mat rotationMatrix = getRotationMatrix2D(center, angle, 1);

  14.     // Create a temporary pattern with a circle
  15.     Mat tempPattern = Mat::zeros(size, size, CV_8UC1);
  16.     circle(tempPattern, center, dotSpacing / 2, Scalar(255), FILLED); // Fill a circle

  17.     // Apply the rotation to the pattern
  18.     warpAffine(tempPattern, pattern, rotationMatrix, pattern.size());
  19. }

  20. // Apply the halftone pattern to an image
  21. void applyHalftonePattern(const Mat &src, Mat &dst, int dotSpacing, double angle) {
  22.     Mat pattern;
  23.     createHalftonePattern(pattern, dotSpacing, angle);

  24.     dst = src.clone();
  25.     for (int y = 0; y < src.rows; y += dotSpacing) {
  26.         for (int x = 0; x < src.cols; x += dotSpacing) {
  27.             Rect roi(x, y, dotSpacing, dotSpacing);
  28.             if (x + dotSpacing <= src.cols && y + dotSpacing <= src.rows) {
  29.                 Mat srcRoi = src(roi);
  30.                 Mat dstRoi = dst(roi);

  31.                 double meanIntensity = mean(srcRoi)[0];
  32.                 // Modulate dot size based on mean intensity of the block
  33.                 double radius = dotSpacing * (1.0 - meanIntensity / 255.0) / 2.0;

  34.                 // Draw dots according to the mean intensity
  35.                 Point center(dotSpacing / 2, dotSpacing / 2);
  36.                 Mat mask = Mat::zeros(srcRoi.size(), srcRoi.type());
  37.                 circle(mask, center, static_cast<int>(radius), Scalar(255), -1);

  38.                 bitwise_and(pattern, mask, dstRoi);
  39.             }
  40.         }
  41.     }
  42. }

  43. int main() {
  44.     Mat img = imread("your_image_path.jpg", IMREAD_GRAYSCALE);
  45.     if (img.empty()) {
  46.         std::cerr << "Error: Cannot load image" << std::endl;
  47.         return -1;
  48.     }

  49.     Mat halftoneImg;
  50.     int dotSpacing = 20;  // Set LPI by controlling the spacing
  51.     double angle = 45.0;  // Angle of the dot grid
  52.     applyHalftonePattern(img, halftoneImg, dotSpacing, angle);

  53.     imshow("Halftone Image", halftoneImg);
  54.     waitKey(0);

  55.     return 0;
  56. }
复制代码


**Key Points:**
- **Pattern Rotation**: This code first creates a pattern with circles, then uses an affine transformation matrix to rotate the entire pattern to the specified angle.
- **Dot Arrangement**: Dots are applied to the image grid, taking into account the mean intensity of the underlying pixels to modulate the dot size.
- **Angle Control**: The `angle` variable controls the overall orientation of the dot grid across the image, determining the visual direction at which the halftone is perceived.

Please adjust the `dotSpacing` and `angle` to experiment with different patterns and densities. This code aims to simulate a classic halftone effect with flexible grid angles.

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-12-7 11:21:51 | 显示全部楼层
FishC 发表于 2024-12-7 11:01
To create a halftone effect with specific angles like 45, 75, or 15 degrees, you can modify the  ...

这段代码处理出来的图片并没有任何半色调网点,我的意思是相邻4个半色调圆点所形成的角度为45度90度15度以及75度不是单独一个圆点的角度,因为同一个圆形网点任何角度都是圆
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-12-7 11:01:07 | 显示全部楼层
cxnet 发表于 2024-12-07 10:55
这段代码的网点角度是90度是否能够设置它的网点为45度 ...


To create a halftone effect with specific angles like 45, 75, or 15 degrees, you can modify the pattern generation to account for these angles in terms of how the dots are placed and sized. The approach involves using a grid system where the angle affects how the pattern is applied across the image.

Here's a simplified approach to control the angle of the dot pattern:

  1. #include <opencv2/opencv.hpp>
  2. #include <iostream>
  3. #include <cmath>

  4. using namespace cv;

  5. // Generates a halftone pattern with a specific angle
  6. void createHalftonePattern(Mat &pattern, int size, double angle) {
  7.     pattern = Mat::zeros(size, size, CV_8UC1);

  8.     double rad = angle * CV_PI / 180.0; // Convert angle to radians
  9.     int center = size / 2;

  10.     for (int y = 0; y < size; ++y) {
  11.         for (int x = 0; x < size; ++x) {
  12.             double dx = x - center;
  13.             double dy = y - center;

  14.             // Rotate the coordinates by the specified angle
  15.             double newX = cos(rad) * dx - sin(rad) * dy;
  16.             double newY = sin(rad) * dx + cos(rad) * dy;

  17.             double distance = sqrt(newX * newX + newY * newY);
  18.             double maxDistance = sqrt(2 * (center * center));

  19.             double value = distance / maxDistance * 255;
  20.             pattern.at<uchar>(y, x) = value;
  21.         }
  22.     }
  23. }

  24. // Applies the halftone pattern to an image
  25. void applyHalftone(const Mat &src, Mat &dst, const Mat &pattern) {
  26.     dst = src.clone();
  27.     for (int y = 0; y < src.rows; ++y) {
  28.         for (int x = 0; x < src.cols; ++x) {
  29.             int patternValue = pattern.at<uchar>(y % pattern.rows, x % pattern.cols);
  30.             dst.at<uchar>(y, x) = src.at<uchar>(y, x) > patternValue ? 255 : 0;
  31.         }
  32.     }
  33. }

  34. int main() {
  35.     Mat img = imread("your_image_path.jpg", IMREAD_GRAYSCALE);
  36.     if (img.empty()) {
  37.         std::cerr << "Error: Cannot load image\n";
  38.         return -1;
  39.     }

  40.     Mat pattern;
  41.     createHalftonePattern(pattern, 10, 45); // Create a 10x10 pattern at a 45-degree angle

  42.     Mat halftoneImg;
  43.     applyHalftone(img, halftoneImg, pattern);

  44.     imshow("Halftone Image", halftoneImg);
  45.     waitKey(0);

  46.     return 0;
  47. }
复制代码


**Key Points:**

- **Rotation Calculation**: The function `createHalftonePattern` generates a pattern based on a specified angle by rotating the coordinates.
- **Pattern Application**: The `applyHalftone` function applies this pattern over the image, creating a halftone effect.
- **Angle Customization**: You can adjust the angle parameter when calling `createHalftonePattern` to achieve different orientations.

This code will create a halftone effect with circular dots aligned according to the specified angle. Adjust the pattern size and angle to get the desired visual effect.

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-12-7 10:55:23 | 显示全部楼层
FishC 发表于 2024-12-6 15:01
要实现这种效果,可以在绘制圆形网点时,先检查网点周围的像素,确保在靠近白色区域的1像素灰色不绘制 ...

这段代码的网点角度是90度是否能够设置它的网点为45度,75度,15度
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-12-6 16:10:17 | 显示全部楼层
cxnet 发表于 2024-12-06 16:09
仍然没有发现半色调圆形网点


To achieve a halftone effect with circular dots, you can use a more advanced approach that involves creating a halftone pattern using a custom dithering matrix. This method allows you to simulate the effect of traditional halftone printing, where dots are arranged in a grid with a specific frequency and angle.

Here's a basic approach to create a halftone effect with OpenCV:

1. **Create a Halftone Pattern**: Use a custom dithering matrix to simulate the halftone effect.
2. **Apply the Pattern**: Use the pattern to threshold the image and create the halftone effect.

Below is a code example that demonstrates this approach:

  1. #include <opencv2/opencv.hpp>
  2. #include <cmath>

  3. using namespace cv;

  4. void createHalftonePattern(Mat &pattern, int size, double angle) {
  5.     pattern = Mat::zeros(size, size, CV_8UC1);
  6.     double rad = angle * CV_PI / 180.0;
  7.     int center = size / 2;
  8.     for (int y = 0; y < size; ++y) {
  9.         for (int x = 0; x < size; ++x) {
  10.             double dx = x - center;
  11.             double dy = y - center;
  12.             double distance = sqrt(dx * dx + dy * dy);
  13.             double theta = atan2(dy, dx) - rad;
  14.             double value = (cos(theta) * distance) / center;
  15.             pattern.at<uchar>(y, x) = static_cast<uchar>((value + 1) * 127.5);
  16.         }
  17.     }
  18. }

  19. void applyHalftone(const Mat &src, Mat &dst, const Mat &pattern) {
  20.     dst = src.clone();
  21.     for (int y = 0; y < src.rows; ++y) {
  22.         for (int x = 0; x < src.cols; ++x) {
  23.             int patternValue = pattern.at<uchar>(y % pattern.rows, x % pattern.cols);
  24.             dst.at<uchar>(y, x) = src.at<uchar>(y, x) > patternValue ? 255 : 0;
  25.         }
  26.     }
  27. }

  28. int main() {
  29.     Mat img = imread("your_image_path.jpg", IMREAD_GRAYSCALE);
  30.     if (img.empty()) {
  31.         printf("Error: Cannot load image
  32. ");
  33.         return -1;
  34.     }

  35.     Mat pattern;
  36.     createHalftonePattern(pattern, 10, 45); // 10x10 pattern with 45-degree angle

  37.     Mat halftoneImg;
  38.     applyHalftone(img, halftoneImg, pattern);

  39.     imshow("Halftone Image", halftoneImg);
  40.     waitKey(0);

  41.     return 0;
  42. }
复制代码


**Key Points:**

- **Halftone Pattern**: The `createHalftonePattern` function generates a pattern based on a specified size and angle. This pattern is used to threshold the image.
- **Pattern Application**: The `applyHalftone` function applies the pattern to the image, creating the halftone effect.
- **Frequency and Angle Control**: The size of the pattern controls the frequency of the dots, and the angle parameter controls the orientation of the pattern.

This approach allows you to simulate a halftone effect with control over the dot frequency and angle, similar to traditional printing techniques. Adjust the pattern size and angle to achieve the desired effect.

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-12-6 16:09:59 | 显示全部楼层
FishC 发表于 2024-12-6 16:06
To achieve a halftone effect with control over dot frequency and angle, you can use a more sophi ...

仍然没有发现半色调圆形网点
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-12-6 16:06:21 | 显示全部楼层
cxnet 发表于 2024-12-06 16:05
处理完没有发现网点,另外没发现控制网点频率和网点角 ...


To achieve a halftone effect with control over dot frequency and angle, you can use a more sophisticated approach that involves generating a halftone pattern using a custom dithering matrix. This method allows you to simulate the effect of traditional halftone printing, where dots are arranged in a grid with a specific frequency and angle.

Here's a basic approach to create a halftone effect with OpenCV:

1. **Create a Halftone Pattern**: Use a custom dithering matrix to simulate the halftone effect.
2. **Apply the Pattern**: Use the pattern to threshold the image and create the halftone effect.

Below is a code example that demonstrates this approach:

  1. #include <opencv2/opencv.hpp>
  2. #include <cmath>

  3. using namespace cv;

  4. void createHalftonePattern(Mat &pattern, int size, double angle) {
  5.     pattern = Mat::zeros(size, size, CV_8UC1);
  6.     double rad = angle * CV_PI / 180.0;
  7.     int center = size / 2;
  8.     for (int y = 0; y < size; ++y) {
  9.         for (int x = 0; x < size; ++x) {
  10.             double dx = x - center;
  11.             double dy = y - center;
  12.             double distance = sqrt(dx * dx + dy * dy);
  13.             double theta = atan2(dy, dx) - rad;
  14.             double value = (cos(theta) * distance) / center;
  15.             pattern.at<uchar>(y, x) = static_cast<uchar>((value + 1) * 127.5);
  16.         }
  17.     }
  18. }

  19. void applyHalftone(const Mat &src, Mat &dst, const Mat &pattern) {
  20.     dst = src.clone();
  21.     for (int y = 0; y < src.rows; ++y) {
  22.         for (int x = 0; x < src.cols; ++x) {
  23.             int patternValue = pattern.at<uchar>(y % pattern.rows, x % pattern.cols);
  24.             dst.at<uchar>(y, x) = src.at<uchar>(y, x) > patternValue ? 255 : 0;
  25.         }
  26.     }
  27. }

  28. int main() {
  29.     Mat img = imread("your_image_path.jpg", IMREAD_GRAYSCALE);
  30.     if (img.empty()) {
  31.         printf("Error: Cannot load image
  32. ");
  33.         return -1;
  34.     }

  35.     Mat pattern;
  36.     createHalftonePattern(pattern, 10, 45); // 10x10 pattern with 45-degree angle

  37.     Mat halftoneImg;
  38.     applyHalftone(img, halftoneImg, pattern);

  39.     imshow("Halftone Image", halftoneImg);
  40.     waitKey(0);

  41.     return 0;
  42. }
复制代码


**Key Points:**

- **Halftone Pattern**: The `createHalftonePattern` function generates a pattern based on a specified size and angle. This pattern is used to threshold the image.
- **Pattern Application**: The `applyHalftone` function applies the pattern to the image, creating the halftone effect.
- **Frequency and Angle Control**: The size of the pattern controls the frequency of the dots, and the angle parameter controls the orientation of the pattern.

This approach allows you to simulate a halftone effect with control over the dot frequency and angle, similar to traditional printing techniques. Adjust the pattern size and angle to achieve the desired effect.

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-12-6 16:05:57 | 显示全部楼层
FishC 发表于 2024-12-6 16:02
要将灰度图像转换为半色调网点,可以使用 Floyd-Steinberg 抖动算法或其他抖动算法。这些算法通过在图 ...

处理完没有发现网点,另外没发现控制网点频率和网点角度控制的地方
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-12-6 16:02:49 | 显示全部楼层
cxnet 发表于 2024-12-06 16:02
靠近白边的网点还是和附近的网点大小不同,除了直接在 ...


要将灰度图像转换为半色调网点,可以使用 Floyd-Steinberg 抖动算法或其他抖动算法。这些算法通过在图像中引入噪声来模拟灰度,从而实现半色调效果。以下是如何使用 OpenCV 和 Floyd-Steinberg 抖动算法来实现这一效果的示例:

  1. #include <opencv2/opencv.hpp>
  2. using namespace cv;

  3. void FloydSteinbergDithering(const Mat &src, Mat &dst) {
  4.     dst = src.clone();
  5.     for (int y = 0; y < src.rows - 1; ++y) {
  6.         for (int x = 1; x < src.cols - 1; ++x) {
  7.             int oldPixel = dst.at<uchar>(y, x);
  8.             int newPixel = oldPixel > 127 ? 255 : 0;
  9.             dst.at<uchar>(y, x) = newPixel;
  10.             int quantError = oldPixel - newPixel;

  11.             dst.at<uchar>(y, x + 1) += quantError * 7 / 16;
  12.             dst.at<uchar>(y + 1, x - 1) += quantError * 3 / 16;
  13.             dst.at<uchar>(y + 1, x) += quantError * 5 / 16;
  14.             dst.at<uchar>(y + 1, x + 1) += quantError * 1 / 16;
  15.         }
  16.     }
  17. }

  18. int main() {
  19.     Mat img = imread("your_image_path.jpg", IMREAD_GRAYSCALE);
  20.     if (img.empty()) {
  21.         printf("Error: Cannot load image
  22. ");
  23.         return -1;
  24.     }

  25.     Mat ditheredImg;
  26.     FloydSteinbergDithering(img, ditheredImg);

  27.     imshow("Dithered Image", ditheredImg);
  28.     waitKey(0);

  29.     return 0;
  30. }
复制代码


**关键点:**

- **Floyd-Steinberg 抖动算法**:通过将量化误差分散到相邻像素来实现抖动效果。
- **灰度图像**:确保输入图像是灰度图像,以便算法正确处理。
- **量化误差传播**:算法将误差分散到右边和下方的像素,以实现更平滑的过渡。

这种方法不直接绘制圆形网点,而是通过抖动算法实现类似的视觉效果。你可以根据需要调整算法的参数或尝试其他抖动算法以获得不同的效果。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-12-6 16:02:34 | 显示全部楼层
FishC 发表于 2024-12-6 15:01
要实现这种效果,可以在绘制圆形网点时,先检查网点周围的像素,确保在靠近白色区域的1像素灰色不绘制 ...

靠近白边的网点还是和附近的网点大小不同,除了直接在图像上绘制圆形网点的方法,还有没有别的直接将灰度图像利用抖动算法转成半色调网点?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-12-6 15:01:35 | 显示全部楼层
cxnet 发表于 2024-12-06 15:01
在绘制圆形网点时,是否可以在千近白色像素的1像素灰 ...


要实现这种效果,可以在绘制圆形网点时,先检查网点周围的像素,确保在靠近白色区域的1像素灰色不绘制网点。可以通过以下步骤实现:

1. **检测白色边缘**:在绘制网点之前,检查网点周围是否有白色像素。
2. **跳过边缘像素**:如果网点靠近白色边缘,则从第二个像素开始绘制。

以下是一个实现思路的代码示例:

  1. #include <opencv2/opencv.hpp>
  2. using namespace cv;

  3. void ConvertToHalftone(const Mat &src, Mat &dst, int lpi) {
  4.     Mat gray;
  5.     cvtColor(src, gray, COLOR_BGR2GRAY);

  6.     dst = Mat::ones(gray.size(), gray.type()) * 255;

  7.     int dotSize = cvRound(25.4 / lpi);
  8.     double maxRadius = dotSize / 2.0 * 1.3; // Enlarge by 1.3 times

  9.     for (int y = 0; y < gray.rows; y += dotSize) {
  10.         for (int x = 0; x < gray.cols; x += dotSize) {
  11.             Rect block(x, y, dotSize, dotSize);
  12.             if (x + dotSize > gray.cols || y + dotSize > gray.rows)
  13.                 continue;

  14.             Mat roi = gray(block);
  15.             Scalar averageIntensity = mean(roi);
  16.             double intensity = averageIntensity.val;

  17.             if (intensity > 2 && intensity < 253) {
  18.                 double scaleFactor = (253 - intensity) / 251.0;
  19.                 double radius = scaleFactor * maxRadius;

  20.                 Point center(cvRound(x + dotSize / 2), cvRound(y + dotSize / 2));

  21.                 // Create a mask for the circle
  22.                 Mat mask = Mat::zeros(block.size(), CV_8UC1);
  23.                 circle(mask, Point(dotSize / 2, dotSize / 2), cvRound(radius), Scalar(255), -1, LINE_AA);

  24.                 // Check for white edges and skip the first pixel
  25.                 for (int i = 1; i < block.height - 1; ++i) {
  26.                     for (int j = 1; j < block.width - 1; ++j) {
  27.                         if (mask.at<uchar>(i, j) == 255) {
  28.                             if (gray.at<uchar>(y + i, x + j) > 240) { // If near white
  29.                                 mask.at<uchar>(i, j) = 0; // Skip this pixel
  30.                             }
  31.                         }
  32.                     }
  33.                 }

  34.                 // Apply the mask to the destination image
  35.                 Mat dstRoi = dst(block);
  36.                 dstRoi.setTo(Scalar(0), mask);

  37.                 // Fill the rest of the block with the original image's color
  38.                 for (int i = 0; i < block.height; ++i) {
  39.                     for (int j = 0; j < block.width; ++j) {
  40.                         if (mask.at<uchar>(i, j) == 0) { // If not part of the dot
  41.                             dst.at<uchar>(y + i, x + j) = gray.at<uchar>(y + i, x + j);
  42.                         }
  43.                     }
  44.                 }
  45.             } else {
  46.                 rectangle(dst, block, Scalar(intensity), FILLED);
  47.             }
  48.         }
  49.     }
  50. }

  51. int main() {
  52.     Mat img = imread("your_image_path.jpg");
  53.     if (img.empty()) {
  54.         printf("Error: Cannot load image
  55. ");
  56.         return -1;
  57.     }

  58.     Mat halftoneImg;
  59.     ConvertToHalftone(img, halftoneImg, 50);

  60.     imshow("Halftone", halftoneImg);
  61.     waitKey(0);

  62.     return 0;
  63. }
复制代码


**关键点:**

- **边缘检测**:在绘制网点时,检查网点周围的像素,确保在靠近白色区域的1像素灰色不绘制网点。
- **跳过边缘像素**:如果网点靠近白色边缘,则从第二个像素开始绘制。
- **掩码应用**:使用掩码来控制哪些像素被绘制。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-12-6 15:01:04 | 显示全部楼层
FishC 发表于 2024-12-6 10:00
要在绘制圆点之后按1像素的大小检测原图块上的黑白颜色,并在目标图像上填充为同样的颜色,可以在绘制 ...

在绘制圆形网点时,是否可以在千近白色像素的1像素灰色不绘制,从第二个像素开始绘制,因为靠近白色的1像素灰色和其它灰色要淡一些绘制出来的点和附近的网点大小不一样,比如一个白色矩形边框里面填充的灰色在靠近矩形边框内上和内左1像素跳过从第2像素开始绘制,而到了框内右侧和框内底部1像素也跳过不绘制网点,这样出来的网点大小就会保持一致
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-12-6 10:58:30 | 显示全部楼层
cxnet 发表于 2024-12-06 10:58
我的意思是我需要放大网点比例1.3倍,但是超出dotSize ...


To handle the situation where the enlarged dot exceeds the `dotSize` and you want to fill the pixels outside the dot with the original image's color, you can follow these steps:

1. **Draw the enlarged dot**: First, draw the dot with the enlarged radius.
2. **Create a mask for the dot**: Use this mask to determine which pixels are part of the dot.
3. **Copy the original image's colors**: For pixels outside the dot but within the `dotSize` block, copy the original image's colors to the destination image.

Here's how you can implement this:

  1. #include <opencv2/opencv.hpp>
  2. using namespace cv;

  3. void ConvertToHalftone(const Mat &src, Mat &dst, int lpi) {
  4.     Mat gray;
  5.     cvtColor(src, gray, COLOR_BGR2GRAY);

  6.     dst = Mat::ones(gray.size(), gray.type()) * 255;

  7.     int dotSize = cvRound(25.4 / lpi);
  8.     double maxRadius = dotSize / 2.0 * 1.3; // Enlarge by 1.3 times

  9.     for (int y = 0; y < gray.rows; y += dotSize) {
  10.         for (int x = 0; x < gray.cols; x += dotSize) {
  11.             Rect block(x, y, dotSize, dotSize);
  12.             if (x + dotSize > gray.cols || y + dotSize > gray.rows)
  13.                 continue;

  14.             Mat roi = gray(block);
  15.             Scalar averageIntensity = mean(roi);
  16.             double intensity = averageIntensity.val;

  17.             if (intensity > 2 && intensity < 253) {
  18.                 double scaleFactor = (253 - intensity) / 251.0;
  19.                 double radius = scaleFactor * maxRadius;

  20.                 Point center(cvRound(x + dotSize / 2), cvRound(y + dotSize / 2));

  21.                 // Create a mask for the circle
  22.                 Mat mask = Mat::zeros(block.size(), CV_8UC1);
  23.                 circle(mask, Point(dotSize / 2, dotSize / 2), cvRound(radius), Scalar(255), -1, LINE_AA);

  24.                 // Draw the circle on the destination image
  25.                 Mat dstRoi = dst(block);
  26.                 dstRoi.setTo(Scalar(0), mask);

  27.                 // Fill the rest of the block with the original image's color
  28.                 for (int i = 0; i < block.height; ++i) {
  29.                     for (int j = 0; j < block.width; ++j) {
  30.                         if (mask.at<uchar>(i, j) == 0) { // If not part of the dot
  31.                             dst.at<uchar>(y + i, x + j) = gray.at<uchar>(y + i, x + j);
  32.                         }
  33.                     }
  34.                 }
  35.             } else {
  36.                 rectangle(dst, block, Scalar(intensity), FILLED);
  37.             }
  38.         }
  39.     }
  40. }

  41. int main() {
  42.     Mat img = imread("your_image_path.jpg");
  43.     if (img.empty()) {
  44.         printf("Error: Cannot load image
  45. ");
  46.         return -1;
  47.     }

  48.     Mat halftoneImg;
  49.     ConvertToHalftone(img, halftoneImg, 50);

  50.     imshow("Halftone", halftoneImg);
  51.     waitKey(0);

  52.     return 0;
  53. }
复制代码


**Key Points:**

- **Mask Creation**: A mask is created for each dot to determine which pixels are part of the dot.
- **Color Filling**: For pixels not part of the dot, the original image's color is copied to the destination image.
- **Boundary Handling**: Ensure that the mask and color filling are correctly applied within the `dotSize` block.

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-12-6 10:58:15 | 显示全部楼层
FishC 发表于 2024-12-6 10:49
为了处理网点半径放大导致的超出`dotSize`的问题,可以在绘制网点时进行边界检查,确保网点不会超出其 ...

我的意思是我需要放大网点比例1.3倍,但是超出dotSize尺寸的网点像素颜色就没办法填充成原图颜色,所以我就想知道超出dotSize块以外的像素怎样填充为原图颜色
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-12-6 10:49:35 | 显示全部楼层
cxnet 发表于 2024-12-06 10:49
我绘制的网点半径统一放大了1.3倍比例,有些网点的直 ...


为了处理网点半径放大导致的超出`dotSize`的问题,可以在绘制网点时进行边界检查,确保网点不会超出其所在的块。以下是一个改进的思路:

1. **边界检查**:在绘制网点时,确保网点的边界不会超出当前块的边界。
2. **调整网点大小**:如果网点的直径超过了`dotSize`,则需要调整网点的半径以适应块的大小。

以下是一个示例代码,展示如何在绘制网点时进行边界检查和调整:

  1. #include <opencv2/opencv.hpp>
  2. using namespace cv;

  3. void ConvertToHalftone(const Mat &src, Mat &dst, int lpi) {
  4.     Mat gray;
  5.     cvtColor(src, gray, COLOR_BGR2GRAY);

  6.     dst = Mat::ones(gray.size(), gray.type()) * 255;

  7.     int dotSize = cvRound(25.4 / lpi);
  8.     double maxRadius = dotSize / 2.0 * 1.3; // 放大1.3倍

  9.     for (int y = 0; y < gray.rows; y += dotSize) {
  10.         for (int x = 0; x < gray.cols; x += dotSize) {
  11.             Rect block(x, y, dotSize, dotSize);
  12.             if (x + dotSize > gray.cols || y + dotSize > gray.rows)
  13.                 continue;

  14.             Mat roi = gray(block);
  15.             Scalar averageIntensity = mean(roi);
  16.             double intensity = averageIntensity.val;

  17.             if (intensity > 2 && intensity < 253) {
  18.                 double scaleFactor = (253 - intensity) / 251.0;
  19.                 double radius = scaleFactor * maxRadius;

  20.                 // 确保网点不会超出块的边界
  21.                 if (radius > dotSize / 2.0) {
  22.                     radius = dotSize / 2.0;
  23.                 }

  24.                 if (radius > 0) {
  25.                     Point center(cvRound(x + dotSize / 2), cvRound(y + dotSize / 2));

  26.                     // Create a mask for the circle
  27.                     Mat mask = Mat::zeros(dst.size(), CV_8UC1);
  28.                     circle(mask, center, cvRound(radius), Scalar(255), -1, LINE_AA);

  29.                     // Apply the mask to the destination image
  30.                     dst.setTo(Scalar(0), mask);

  31.                     // Check each pixel in the block and fill the destination image
  32.                     for (int i = 0; i < block.height; ++i) {
  33.                         for (int j = 0; j < block.width; ++j) {
  34.                             int pixelValue = gray.at<uchar>(y + i, x + j);
  35.                             if (pixelValue > 240) { // Assuming white
  36.                                 dst.at<uchar>(y + i, x + j) = 255;
  37.                             } else {
  38.                                 dst.at<uchar>(y + i, x + j) = 0;
  39.                             }
  40.                         }
  41.                     }
  42.                 }
  43.             } else {
  44.                 rectangle(dst, block, Scalar(intensity), FILLED);
  45.             }
  46.         }
  47.     }
  48. }

  49. int main() {
  50.     Mat img = imread("your_image_path.jpg");
  51.     if (img.empty()) {
  52.         printf("Error: Cannot load image
  53. ");
  54.         return -1;
  55.     }

  56.     Mat halftoneImg;
  57.     ConvertToHalftone(img, halftoneImg, 50);

  58.     imshow("Halftone", halftoneImg);
  59.     waitKey(0);

  60.     return 0;
  61. }
复制代码


**关键点:**

- 在计算`radius`时,确保其不会超过`dotSize / 2.0`。
- 通过这种方式,网点将被限制在其所在的块内,从而避免超出边界的问题。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-9-23 09:15

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表