鱼C论坛

 找回密码
 立即注册
查看: 38|回复: 3

图片处理

[复制链接]
发表于 昨天 20:41 | 显示全部楼层 |阅读模式

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

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

x
在c++中我用下面代码可以在不旋转图片的情况下给灰色Mat图像转为圆形网点(旋转图像加网的情况下,图像旋转后会产生锯齿,所以不适合)。
但现在有2个问题
第一,所有颜色都是一样大的网点,实际上应该按照颜色深浅不同而生成不同大小的网点
第二,纯黑色(即95%以上颜色)不加网,请问应该怎样修改?

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

const double PI = 3.141592653589793;

void createCircularDotScreen(cv::Mat& dst, const cv::Mat& src, double angle_deg, double lpi) {
    double angle_rad = angle_deg * PI / 180.0;
    double dpi = 96.0; // 假设屏幕DPI为96
    double spacing = dpi / lpi; // 计算网点间距(像素)
   
    dst.create(src.size(), CV_8UC1);
    cv::Point2f center(src.cols / 2.0f, src.rows / 2.0f);

    for (int y = 0; y < src.rows; ++y) {
        for (int x = 0; x < src.cols; ++x) {
            // 坐标平移至中心
            float x_rel = x - center.x;
            float y_rel = y - center.y;

            // 15度倾斜变换
            float x_rot = x_rel * cos(angle_rad) - y_rel * sin(angle_rad);
            float y_rot = x_rel * sin(angle_rad) + y_rel * cos(angle_rad);

            // 计算网点中心位置
            float x_center = round(x_rot / spacing) * spacing;
            float y_center = round(y_rot / spacing) * spacing;

            // 计算当前点到网点的距离
            float distance = sqrt(pow(x_rot - x_center, 2) + pow(y_rot - y_center, 2));
            float radius = spacing / 2.0;

            // 获取原图像素值(0-255)
            uchar pixel = src.at<uchar>(y, x);
            float threshold = radius * (1.0 - pixel / 255.0);

            // 决定是否填充网点
            dst.at<uchar>(y, x) = (distance <= threshold) ? 0 : 255;
        }
    }
}

int main() {
    cv::Mat src = cv::imread("input.jpg", cv::IMREAD_GRAYSCALE);
    if (src.empty()) return -1;

    cv::Mat dotPattern;
    createCircularDotScreen(dotPattern, src, 15.0, 60.0);

    cv::imwrite("output.jpg", dotPattern);
    return 0;
}
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 昨天 20:43 | 显示全部楼层
针对您提出的两个问题,我来提供修改方案:

问题1:根据颜色深浅生成不同大小的网点
需要根据灰度值调整网点半径,颜色越深网点越大

问题2:纯黑色不加网
需要添加阈值判断,灰度值低于某个阈值时直接设为黑色


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

  3. const double PI = 3.141592653589793;

  4. void createCircularDotScreen(cv::Mat& dst, const cv::Mat& src, double angle_deg, double lpi) {
  5.     double angle_rad = angle_deg * PI / 180.0;
  6.     double dpi = 96.0;
  7.     double spacing = dpi / lpi;
  8.    
  9.     dst.create(src.size(), CV_8UC1);
  10.     cv::Point2f center(src.cols / 2.0f, src.rows / 2.0f);

  11.     for (int y = 0; y < src.rows; ++y) {
  12.         for (int x = 0; x < src.cols; ++x) {
  13.             // 获取原图像素值
  14.             uchar pixel = src.at<uchar>(y, x);
  15.             
  16.             // 问题2:纯黑色不加网(灰度值低于13,约95%黑色)
  17.             if (pixel <= 13) {
  18.                 dst.at<uchar>(y, x) = 0; // 直接设为黑色
  19.                 continue;
  20.             }
  21.             
  22.             // 坐标变换
  23.             float x_rel = x - center.x;
  24.             float y_rel = y - center.y;
  25.             float x_rot = x_rel * cos(angle_rad) - y_rel * sin(angle_rad);
  26.             float y_rot = x_rel * sin(angle_rad) + y_rel * cos(angle_rad);

  27.             // 计算网点中心位置
  28.             float x_center = round(x_rot / spacing) * spacing;
  29.             float y_center = round(y_rot / spacing) * spacing;

  30.             // 计算距离
  31.             float distance = sqrt(pow(x_rot - x_center, 2) + pow(y_rot - y_center, 2));
  32.             
  33.             // 问题1:根据灰度值动态调整网点半径
  34.             // 灰度值越大(颜色越浅)网点越小,反之越大
  35.             float max_radius = spacing / 2.0;
  36.             float min_radius = spacing / 10.0; // 最小半径防止网点消失
  37.             float radius = min_radius + (max_radius - min_radius) * (1.0 - pixel / 255.0);

  38.             // 生成网点
  39.             if (distance <= radius) {
  40.                 dst.at<uchar>(y, x) = 255; // 白色网点
  41.             } else {
  42.                 dst.at<uchar>(y, x) = 0;   // 黑色背景
  43.             }
  44.         }
  45.     }
  46. }
复制代码


主要修改说明:

  • 动态网点半径:根据灰度值 pixel 计算半径,颜色越深(pixel值越小)网点越大
  • 纯黑色处理:当灰度值 ≤ 13(约95%黑色)时,直接设为黑色,不加网点
  • 半径范围控制:设置最小半径防止浅色区域网点消失,最大半径为间距的一半


您可以根据实际效果调整 min_radius 和纯黑色的阈值(当前为13)。

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

使用道具 举报

发表于 昨天 20:59 | 显示全部楼层
建议用code形式
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 22:44 | 显示全部楼层

谢谢,不过我不会,能帮忙写个例子吗?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-10-14 04:24

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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