鱼C论坛

 找回密码
 立即注册
楼主: cxnet

图像转换

[复制链接]
 楼主| 发表于 2024-12-5 16:05:25 | 显示全部楼层
FishC 发表于 2024-12-5 16:03
为了确保网点在遇到白色区域时停止绘制,可以在绘制网点时使用掩码来限制绘制区域。以下是一个改进的实 ...

还是一样的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-12-5 16:05:45 | 显示全部楼层


要确保网点在遇到白色区域时停止绘制,可以通过以下步骤来实现:

1. **检测白色区域**:在绘制网点之前,检查网点所在区域是否包含白色像素。
2. **裁剪网点**:如果网点边缘与白色区域重叠,则只在非白色区域绘制网点。

以下是一个改进的实现思路:
#include <opencv2/opencv.hpp>
using namespace cv;

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

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

    int dotSize = cvRound(25.4 / lpi);
    double maxRadius = dotSize / 2.0;

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

            Mat roi = gray(block);
            Scalar averageIntensity = mean(roi);
            double intensity = averageIntensity.val[0];

            if (intensity > 2 && intensity < 253) {
                double scaleFactor = (253 - intensity) / 251.0;
                double radius = scaleFactor * maxRadius;
                if (radius > 0) {
                    Point center(cvRound(x + dotSize / 2), cvRound(y + dotSize / 2));

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

                    // Check for white areas in the original image
                    Mat whiteArea;
                    inRange(src(block), Scalar(240, 240, 240), Scalar(255, 255, 255), whiteArea);

                    // Invert the white area mask
                    bitwise_not(whiteArea, whiteArea);

                    // Apply the mask to the circle
                    bitwise_and(mask(block), whiteArea, mask(block));

                    // Draw the circle on the destination image
                    dst.setTo(Scalar(0), mask);
                }
            } else {
                rectangle(dst, block, Scalar(intensity), FILLED);
            }
        }
    }
}

int main() {
    Mat img = imread("your_image_path.jpg");
    if (img.empty()) {
        printf("Error: Cannot load image
");
        return -1;
    }

    Mat halftoneImg;
    ConvertToHalftone(img, halftoneImg, 50);

    imshow("Halftone", halftoneImg);
    waitKey(0);

    return 0;
}

**关键点:**

- 使用`inRange`函数检测白色区域。
- 使用`bitwise_and`函数将白色区域的掩码应用于网点,以确保网点不会覆盖白色区域。
- 通过这种方式,网点将被裁剪以适应白色区域,从而避免侵蚀白色文字或线条。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-12-6 09:45:45 | 显示全部楼层
FishC 发表于 2024-12-4 11:17
为了实现类似Photoshop中的Halftone效果,需要更加细致地控制图像点阵大小、形状和位置。以下的代码尝 ...

怎样在绘制圆点之后按1像素的大小检测原图块上黑白颜色,并在dst图像上填充为同样的颜色
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-12-6 10:00:25 | 显示全部楼层
cxnet 发表于 2024-12-06 09:45
怎样在绘制圆点之后按1像素的大小检测原图块上黑白颜 ...


要在绘制圆点之后按1像素的大小检测原图块上的黑白颜色,并在目标图像上填充为同样的颜色,可以在绘制圆点后逐像素检查原图像的颜色,并将其应用到目标图像上。以下是一个实现思路:
#include <opencv2/opencv.hpp>
using namespace cv;

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

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

    int dotSize = cvRound(25.4 / lpi);
    double maxRadius = dotSize / 2.0;

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

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

            if (intensity > 2 && intensity < 253) {
                double scaleFactor = (253 - intensity) / 251.0;
                double radius = scaleFactor * maxRadius;
                if (radius > 0) {
                    Point center(cvRound(x + dotSize / 2), cvRound(y + dotSize / 2));

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

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

                    // Check each pixel in the block and fill the destination image
                    for (int i = 0; i < block.height; ++i) {
                        for (int j = 0; j < block.width; ++j) {
                            int pixelValue = gray.at<uchar>(y + i, x + j);
                            if (pixelValue > 240) { // Assuming white
                                dst.at<uchar>(y + i, x + j) = 255;
                            } else {
                                dst.at<uchar>(y + i, x + j) = 0;
                            }
                        }
                    }
                }
            } else {
                rectangle(dst, block, Scalar(intensity), FILLED);
            }
        }
    }
}

int main() {
    Mat img = imread("your_image_path.jpg");
    if (img.empty()) {
        printf("Error: Cannot load image
");
        return -1;
    }

    Mat halftoneImg;
    ConvertToHalftone(img, halftoneImg, 50);

    imshow("Halftone", halftoneImg);
    waitKey(0);

    return 0;
}

**关键点:**

- 在绘制圆点后,逐像素检查原图像的颜色。
- 使用`dst.at<uchar>(y + i, x + j)`来设置目标图像的像素值。
- 通过这种方式,确保在白色区域不绘制黑色圆点,并保持原图像的白色区域。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

我绘制的网点半径统一放大了1.3倍比例,有些网点的直径会超过dotSize的大小就没办法填成原图的颜色,这种情况应该怎么处理
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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


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

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

以下是一个示例代码,展示如何在绘制网点时进行边界检查和调整:
#include <opencv2/opencv.hpp>
using namespace cv;

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

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

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

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

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

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

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

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

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

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

                    // Check each pixel in the block and fill the destination image
                    for (int i = 0; i < block.height; ++i) {
                        for (int j = 0; j < block.width; ++j) {
                            int pixelValue = gray.at<uchar>(y + i, x + j);
                            if (pixelValue > 240) { // Assuming white
                                dst.at<uchar>(y + i, x + j) = 255;
                            } else {
                                dst.at<uchar>(y + i, x + j) = 0;
                            }
                        }
                    }
                }
            } else {
                rectangle(dst, block, Scalar(intensity), FILLED);
            }
        }
    }
}

int main() {
    Mat img = imread("your_image_path.jpg");
    if (img.empty()) {
        printf("Error: Cannot load image
");
        return -1;
    }

    Mat halftoneImg;
    ConvertToHalftone(img, halftoneImg, 50);

    imshow("Halftone", halftoneImg);
    waitKey(0);

    return 0;
}

**关键点:**

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

我的意思是我需要放大网点比例1.3倍,但是超出dotSize尺寸的网点像素颜色就没办法填充成原图颜色,所以我就想知道超出dotSize块以外的像素怎样填充为原图颜色
想知道小甲鱼最近在做啥?请访问 -> 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:
#include <opencv2/opencv.hpp>
using namespace cv;

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

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

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

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

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

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

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

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

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

                // Fill the rest of the block with the original image's color
                for (int i = 0; i < block.height; ++i) {
                    for (int j = 0; j < block.width; ++j) {
                        if (mask.at<uchar>(i, j) == 0) { // If not part of the dot
                            dst.at<uchar>(y + i, x + j) = gray.at<uchar>(y + i, x + j);
                        }
                    }
                }
            } else {
                rectangle(dst, block, Scalar(intensity), FILLED);
            }
        }
    }
}

int main() {
    Mat img = imread("your_image_path.jpg");
    if (img.empty()) {
        printf("Error: Cannot load image
");
        return -1;
    }

    Mat halftoneImg;
    ConvertToHalftone(img, halftoneImg, 50);

    imshow("Halftone", halftoneImg);
    waitKey(0);

    return 0;
}

**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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

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

使用道具 举报

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


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

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

以下是一个实现思路的代码示例:
#include <opencv2/opencv.hpp>
using namespace cv;

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

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

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

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

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

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

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

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

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

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

                // Fill the rest of the block with the original image's color
                for (int i = 0; i < block.height; ++i) {
                    for (int j = 0; j < block.width; ++j) {
                        if (mask.at<uchar>(i, j) == 0) { // If not part of the dot
                            dst.at<uchar>(y + i, x + j) = gray.at<uchar>(y + i, x + j);
                        }
                    }
                }
            } else {
                rectangle(dst, block, Scalar(intensity), FILLED);
            }
        }
    }
}

int main() {
    Mat img = imread("your_image_path.jpg");
    if (img.empty()) {
        printf("Error: Cannot load image
");
        return -1;
    }

    Mat halftoneImg;
    ConvertToHalftone(img, halftoneImg, 50);

    imshow("Halftone", halftoneImg);
    waitKey(0);

    return 0;
}

**关键点:**

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

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

使用道具 举报

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


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

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

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

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

    Mat ditheredImg;
    FloydSteinbergDithering(img, ditheredImg);

    imshow("Dithered Image", ditheredImg);
    waitKey(0);

    return 0;
}

**关键点:**

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

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

处理完没有发现网点,另外没发现控制网点频率和网点角度控制的地方
想知道小甲鱼最近在做啥?请访问 -> 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:
#include <opencv2/opencv.hpp>
#include <cmath>

using namespace cv;

void createHalftonePattern(Mat &pattern, int size, double angle) {
    pattern = Mat::zeros(size, size, CV_8UC1);
    double rad = angle * CV_PI / 180.0;
    int center = size / 2;
    for (int y = 0; y < size; ++y) {
        for (int x = 0; x < size; ++x) {
            double dx = x - center;
            double dy = y - center;
            double distance = sqrt(dx * dx + dy * dy);
            double theta = atan2(dy, dx) - rad;
            double value = (cos(theta) * distance) / center;
            pattern.at<uchar>(y, x) = static_cast<uchar>((value + 1) * 127.5);
        }
    }
}

void applyHalftone(const Mat &src, Mat &dst, const Mat &pattern) {
    dst = src.clone();
    for (int y = 0; y < src.rows; ++y) {
        for (int x = 0; x < src.cols; ++x) {
            int patternValue = pattern.at<uchar>(y % pattern.rows, x % pattern.cols);
            dst.at<uchar>(y, x) = src.at<uchar>(y, x) > patternValue ? 255 : 0;
        }
    }
}

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

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

    Mat halftoneImg;
    applyHalftone(img, halftoneImg, pattern);

    imshow("Halftone Image", halftoneImg);
    waitKey(0);

    return 0;
}

**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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> 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 ...

仍然没有发现半色调圆形网点
想知道小甲鱼最近在做啥?请访问 -> 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:
#include <opencv2/opencv.hpp>
#include <cmath>

using namespace cv;

void createHalftonePattern(Mat &pattern, int size, double angle) {
    pattern = Mat::zeros(size, size, CV_8UC1);
    double rad = angle * CV_PI / 180.0;
    int center = size / 2;
    for (int y = 0; y < size; ++y) {
        for (int x = 0; x < size; ++x) {
            double dx = x - center;
            double dy = y - center;
            double distance = sqrt(dx * dx + dy * dy);
            double theta = atan2(dy, dx) - rad;
            double value = (cos(theta) * distance) / center;
            pattern.at<uchar>(y, x) = static_cast<uchar>((value + 1) * 127.5);
        }
    }
}

void applyHalftone(const Mat &src, Mat &dst, const Mat &pattern) {
    dst = src.clone();
    for (int y = 0; y < src.rows; ++y) {
        for (int x = 0; x < src.cols; ++x) {
            int patternValue = pattern.at<uchar>(y % pattern.rows, x % pattern.cols);
            dst.at<uchar>(y, x) = src.at<uchar>(y, x) > patternValue ? 255 : 0;
        }
    }
}

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

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

    Mat halftoneImg;
    applyHalftone(img, halftoneImg, pattern);

    imshow("Halftone Image", halftoneImg);
    waitKey(0);

    return 0;
}

**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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

这段代码的网点角度是90度是否能够设置它的网点为45度,75度,15度
想知道小甲鱼最近在做啥?请访问 -> 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:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cmath>

using namespace cv;

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

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

    for (int y = 0; y < size; ++y) {
        for (int x = 0; x < size; ++x) {
            double dx = x - center;
            double dy = y - center;

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

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

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

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

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

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

    Mat halftoneImg;
    applyHalftone(img, halftoneImg, pattern);

    imshow("Halftone Image", halftoneImg);
    waitKey(0);

    return 0;
}

**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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> 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度不是单独一个圆点的角度,因为同一个圆形网点任何角度都是圆
想知道小甲鱼最近在做啥?请访问 -> 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.
#include <opencv2/opencv.hpp>
#include <iostream>
#include <cmath>

using namespace cv;

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

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

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

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

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

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

    dst = src.clone();
    for (int y = 0; y < src.rows; y += dotSpacing) {
        for (int x = 0; x < src.cols; x += dotSpacing) {
            Rect roi(x, y, dotSpacing, dotSpacing);
            if (x + dotSpacing <= src.cols && y + dotSpacing <= src.rows) {
                Mat srcRoi = src(roi);
                Mat dstRoi = dst(roi);

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

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

                bitwise_and(pattern, mask, dstRoi);
            }
        }
    }
}

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

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

    imshow("Halftone Image", halftoneImg);
    waitKey(0);

    return 0;
}

**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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-22 13:24

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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