如何进行这种图像转换?

2024-03-09

我有一个带有模糊边缘的彩色斑点的图像(上半部分),我想为其创建一个由直线组成的轮廓(下半部分):

填充形状没有问题,只需添加轮廓即可。如有必要,可以将其转换为黑白图像。

谁能指出一个可以做到这一点的简单转换/程序?最好是我可以轻松找到代码示例的东西。


我想用 C++ 为你编码,而不是像我的其他答案那样使用命令行,所以我把它作为一个不同的答案。最重要的是,它实际上还实现了 Douglas-Peucker 算法,并且出于有趣和良好的考虑,还对其进行了动画处理。

////////////////////////////////////////////////////////////////////////////////
// main.cpp
// Mark Setchell
// To find a blob in an image and generate line segments that describe it,
// Use ImageMagick Magick++ and Ramer-Douglas-Peucker algorithm.
// https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker-algorithm
//
// function DouglasPeucker(PointList[], epsilon)
//   // Find the point with the maximum distance
//   dmax = 0
//   index = 0
//   end = length(PointList)
//   for i = 2 to ( end - 1) {
//      d = perpendicularDistance(PointList[i], Line(PointList[1], PointList[end])) 
//      if ( d > dmax ) {
//         index = i
//         dmax = d
//      }
//   }
//   // If max distance is greater than epsilon, recursively simplify
//   if ( dmax > epsilon ) {
//      // Recursive call
//      recResults1[] = DouglasPeucker(PointList[1...index], epsilon)
//      recResults2[] = DouglasPeucker(PointList[index...end], epsilon)

//      // Build the result list
//      ResultList[] = {recResults1[1...length(recResults1)-1], recResults2[1...length(recResults2)]}
//   } else {
//       ResultList[] = {PointList[1], PointList[end]}
//   }
//   // Return the result
//  return ResultList[]
//  end
//
////////////////////////////////////////////////////////////////////////////////

#include <Magick++.h> 
#include <iostream> 
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <cassert>
#include <cstdio>
#include <iostream>
#include <cmath>

using namespace std;
using namespace Magick; 

// Global debug image
   Image DEBUG_IMAGE;
   int   DEBUG_NUM=0;
   char  DEBUG_NAME[64];

#define DEBUG(img) {sprintf(DEBUG_NAME,"debug-%04d.png",DEBUG_NUM++);img.write(DEBUG_NAME);}

// Point class
class Point {
private:
        double px,py;
public:
        // Constructor 
        Point(double x = 0.0, double y = 0.0) {
       px = x;
       py = y;
        }

        // Getters
        double x() { return px; }
        double y() { return py; }
};

// Line class
class Line {
private:
        Point start,end;
public:
        // Constructor 
        Line(Point a=Point(0,0), Point b=Point(0,0)){
           start=a;
           end=b;
        }
        // Getters
        double startx() { return start.x(); }
        double starty() { return start.y(); }
        double endx()   { return end.x();   }
        double endy()   { return end.y();   }
    double DistanceTo(Point p){
       double y2my1 = end.y() - start.y();
       double x2mx1 = end.x() - start.x();
       double numerator = fabs(y2my1*p.x() - x2mx1*p.y() + end.x()*start.y() - end.y()*start.x());
       double denominator = sqrt(y2my1*y2my1 + x2mx1*x2mx1);
       return numerator/denominator;
        }
};

void DouglasPeucker(vector<Point>& PointList,int startindex,int endindex,double epsilon,vector<Line>& Results){
   // Find the point with the maximum distance
   double d,dmax=0;
   int i,index;
   Line line(PointList[startindex],PointList[endindex]);

   for(i=startindex+1;i<endindex;i++){
      d=line.DistanceTo(PointList[i]) ;
      if(d>dmax){
         index=i;
         dmax=d;
      }
   }

   // If max distance is greater than epsilon, recursively simplify
   if ( dmax > epsilon ) {
      // Recursive call to do left and then right parts
      DouglasPeucker(PointList,startindex,index,epsilon,Results);
      DouglasPeucker(PointList,index,endindex,epsilon,Results);
   } else {
      Results.push_back(line);
      // Rest of else statement is just generating debug image
      std::list<Magick::Drawable> drawList;
      drawList.push_back(DrawableStrokeColor("blue"));
      drawList.push_back(DrawableStrokeWidth(1));
      drawList.push_back(DrawableLine(line.startx(),line.starty(),line.endx(),line.endy()));
      DEBUG_IMAGE.draw(drawList);
      DEBUG(DEBUG_IMAGE);
   }
}


int main(int argc,char **argv) 
{ 
   InitializeMagick(*argv);

   // Create some colours
   Color black   = Color("rgb(0,0,0)");
   Color white   = Color("rgb(65535,65535,65535)");
   Color red     = Color("rgb(65535,0,0)");
   Color green   = Color("rgb(0,65535,0)");
   Color blue    = Color("rgb(0,0,65535)");

   // Create a fuzz factor scaling
   assert(QuantumRange==65535);
   const double fuzzscale = QuantumRange/100;

   // Load wave image
   Image image("wave.jpg");
   int w = image.columns();
   int h = image.rows();
   cout << "Dimensions: " << w << "x" << h << endl;

   // Copy for debug purposes
   DEBUG_IMAGE=image;

   // Fill top-left greyish area of image with green
   image.colorFuzz(50*fuzzscale);
   image.opaque(white,green);
   DEBUG(image);

   // Fill bottom-right blackish area of image with blue
   image.colorFuzz(20*fuzzscale);
   image.opaque(black,blue);
   DEBUG(image);

   // Fill rest of image with red
   image.colorFuzz(81*fuzzscale);
   image.opaque(red,red);
   DEBUG(image);

   // Median filter to remove jaggies
   image.medianFilter(25);
   DEBUG(image);

   // Find red-green edge by cloning, making blue red, then looking for edges
   std::vector<Point> RGline;
   Image RGimage=image;
   RGimage.opaque(blue,red);
   DEBUG(RGimage);
   RGimage.type(GrayscaleType);
   DEBUG(RGimage);
   RGimage.normalize();
   DEBUG(RGimage);
   RGimage.edge(1);
   DEBUG(RGimage);

   // Now pass over the image collecting white pixels (from red-green edge)
   // Ignore a single row at top & bottom and a single column at left & right edges
   // Get a "pixel cache" for the entire image
   PixelPacket *pixels = RGimage.getPixels(0, 0, w, h);
   int x,y;

   for(x=1; x<w-2; x++){
      for(y=1; y<h-2; y++){
         Color color = pixels[w * y + x];
         // Collect white "edge" pixels
         if(color.redQuantum()==65535){
            RGline.push_back(Point(x,y));
         }
      }
   }
   cout << "RGline has " << RGline.size() << " elements" << endl;

   // Results - a vector of line segments
   std::vector<Line> Results;

   // epsilon = Max allowable deviation from straight line in pixels
   // Make epsilon smaller for more, shorter, more accurate lines
   // Make epsilon larger for fewer, more approximate lines
   double epsilon=18;
   DouglasPeucker(RGline,0,RGline.size()-1,epsilon,Results);
   int lines1=Results.size();
   cout << "Upper boundary mapped to " << lines1 << " line segments (epsilon=" << epsilon << ")" << endl;

   // Find red-blue edge by cloning, making green red, then looking for edges
   std::vector<Point> RBline;
   Image RBimage=image;
   RBimage.opaque(green,red);
   DEBUG(RBimage);
   RBimage.type(GrayscaleType);
   DEBUG(RBimage);
   RBimage.normalize();
   DEBUG(RBimage);
   RBimage.edge(1);
   DEBUG(RBimage);

   // Now pass over the image collecting white pixels (from red-green edge)
   // Ignore a single row at top & bottom and a single column at left & right edges
   // Get a "pixel cache" for the entire image
   pixels = RBimage.getPixels(0, 0, w, h);

   for(x=1; x<w-2; x++){
      for(y=1; y<h-2; y++){
         Color color = pixels[w * y + x];
         // Collect white "edge" pixels
         if(color.redQuantum()==65535){
            RBline.push_back(Point(x,y));
         }
      }
   }
   cout << "RBline has " << RBline.size() << " elements" << endl;

   DouglasPeucker(RBline,0,RBline.size()-1,epsilon,Results);
   int lines2=Results.size() - lines1;
   cout << "Lower boundary mapped to " << lines2 << " line segments (epsilon=" << epsilon << ")" << endl;
}

My Makefile看起来像这样:

main:   main.cpp
        clang++ -std=gnu++11  -Wall -pedantic  main.cpp -o main $$(Magick++-config --cppflags --cxxflags --ldflags --libs)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何进行这种图像转换? 的相关文章

  • 图像未显示在从 HTML 创建的 PDF 上

    我想动态创建 PDF 这意味着我将从 Google Drive 获取文件 然后将它们放入 HTML 代码中 并尝试从中创建 PDF 一切工作正常 除了图像没有显示 我现在正在做的是 从 HTML 字符串创建 HtmlOutput 获取该 H
  • java设置图像的分辨率和打印尺寸

    我编写了一个程序 生成一个 BufferedImage 以显示在屏幕上 然后打印 图像的一部分包括 1 像素宽的网格线 即 一行为1个像素 行与行之间大约有10个像素 由于屏幕分辨率的原因 图像显示得比这大得多 每行有几个像素 我想将其绘制
  • 从 imread 返回的 ndims

    我正在从文件夹中选取图像 尺寸为128 128 为此 我使用以下代码行 FileName PathName uigetfile jpg Select the Cover Image file fullfile PathName FileNa
  • 从剪贴板获取图像 Awt 与 FX

    最近 我们的 Java FX 应用程序无法再从剪贴板读取图像 例如 用户在 Microsofts Paint 中选择图像的一部分并按复制 我不是在谈论复制的图像文件 它们工作得很好 我很确定它过去已经有效 但我仍然需要验证这一点 尽管如此
  • JS - 如何将图像对象变成灰度并显示它

    基本上 当单击按钮时 它会告诉移动设备转到相机 一旦相机拍照 它就会给我图像数据 它被称为数据 URL 吗 这是我处理它的代码 var imagesrc data image jpeg base64 imageData var myimag
  • 在python中将二维数组转换为彩色图像

    我有这样的二维整数列表 list1 1 30 50 21 45 9 97 321 100 接下来我将把它转换为 numpy 数组 myarr np asarray list1 接下来我将使用 PIL 将其转换为图像 如下所示 img Ima
  • 将 System.Drawing.Image 转换为 System.Windows.Media.ImageSource 但没有结果

    我想在我的 WPF 应用程序中将 Image 转换为 ImageSource 我使用正常工作的 Code128 库 已在 WinForms 应用程序中检查 下面的函数返回具有适当大小的 ImageSource 但没有任何内容可见 priva
  • 仅获取图像中的外部轮廓

    我有这段代码 可以在图像中绘制轮廓 但我只需要外部轮廓 import cv2 import numpy as np camino C Users Usuario Documents Deteccion de Objetos 123 jpg
  • 直方图均衡结果

    I am trying to code histogram equalization by my self but the results are different from the built in function in matlab
  • 在单个显示器中绘制多个 jpeg 图像

    我需要在单个组合显示器 或画布 中绘制和显示多个 jpeg 图像 例如 假设我有图像 a b c d jpg 每个图像的大小不同 我想将它们绘制在 2x2 网格的一页上 能够为每个子图设置标题也很好 我一直在彻底寻找解决方案 但不知道如何去
  • 在Android内存中存储gif图像

    我对安卓还很陌生 我想将图像保存到内存中 然后从内存中检索图像并将其加载到图像视图中 我已使用以下代码成功将图像存储在内存中 void saveImage String fileName img cnt jpg File file new
  • 在 JavaScript 函数中加载图像

    我有获取图像像素颜色的功能 function getImage imgsrc var img img src imgsrc var imageMap new Object img load function var canvas
  • JavaFX:将像素写入 PixelWriter 的最快方法

    我正在寻找最快的方式来写入像素javafx scene image Image 写信给BufferedImage的后备数组要快得多 至少在我制作的测试图像上 只花了大约 20 毫秒BufferedImage WritableImage另一方
  • PIL - 需要抖动,但限制调色板会导致问题

    我是 Python 新手 正在尝试使用 PIL 来执行 Arduino 项目所需的解析任务 这个问题涉及到Image convert 方法以及调色板 抖动等选项 我有一些硬件能够一次仅显示 16 种颜色的图像 但它们可以指定为 RGB 三元
  • Java .drawImage:如何“取消绘制”或删除图像?

    我需要在程序运行时不断在不同位置重绘某个图像 因此 我设置了一个 while 循环 该循环应该在屏幕上移动图像 但它只是一遍又一遍地重新绘制图像 我究竟做错了什么 有没有办法在将旧图像绘制到新位置之前删除旧图像 JFrame frame b
  • 保存为 HDF5 的图像未着色

    我目前正在开发一个将文本文件和 jpg 图像转换为 HDF5 格式的程序 用HDFView 3 0打开 似乎图像仅以灰度保存 hdf h5py File Sample h5 img Image open Image jpg data np
  • 使用 mongoose 通过 React 应用程序将图像上传到 mongodb 数据库

    我正在为找到的对象创建一个反应应用程序 我想允许用户上传这些对象的照片 我尝试使用 axios 通过 post 请求将图像发送到猫鼬服务器 但它不起作用 这就是我如何将图像存储在带有预览的 React 组件中 handleImage eve
  • 使用 PHP 中的 GD 库在图像上绘图

    我创建了一个代码来生成随机图案图像 它创建一个具有给定宽度和高度的图像 并用 40x40 像素的小矩形填充它 这是我的代码
  • 下载后从谷歌照片库检索图像

    我正在发起从图库中获取照片的意图 当我在图库中使用 Nexus 谷歌照片应用程序时 一切正常 但如果图像不在手机上 在 Google Photos 在线服务上 它会为我下载 选择图像后 我将图像发送到另一个活动进行裁剪 但在下载的情况下 发
  • 在Python中调整图像大小

    我有一张尺寸为 288 352 的图像 我想将其大小调整为 160 240 我尝试了以下代码 im imread abc png img im resize 160 240 Image ANTIALIAS 但它给出了一个错误TypeErro

随机推荐

  • 如何实现自定义“fmt::Debug”特征?

    我想你会做这样的事情 extern crate uuid use uuid Uuid use std fmt Formatter use std fmt Debug derive Debug struct BlahLF id Uuid im
  • Spring 的 Joda Time 日期时间格式无效

    我有一个项目已经使用 Jackson Hibernate4Module 进行对象映射 现在 我想在项目中使用 Joda Time 并添加了 joda time joda time hibernate jackson datatype jod
  • 无法在 iTunes Connect 中上传我的应用程序的屏幕截图 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 由于更新 我尝试更改应用程序的屏幕截图 但苹果给了我错误 发生网络超时错误 请稍后再试 有什么帮助吗 请将浏览器切换到其他浏览器 然后是
  • Android Studio 键盘快捷键控制

    谁能给我一些 Android Studio 键盘快捷键所有控件的建议或链接 Move to File gt Settings gt Keymap并改变Keymaps设置到eclipse 这样就可以像在eclipse中一样使用快捷键了
  • Mathematica“AppendTo”函数问题

    我是 Mathematica 的新手 在向数据表添加列时遇到了重大故障 我在 Vista 中运行 Mathematica 7 我在RFD上花了很多时间才来这里问 我有一个包含三列五行的数据表 mydata 我正在尝试将两个包含五个元素的列表
  • 数组切片返回 [object Object] 而不是值

    我试图获取特定 div 被删除时的位置 在一些帮助下 我整理了下面的代码 我在最后一点添加了尝试获取特定值 但它只是返回 object Object 而不是 0 0 或 0 120 之类的东西 那么问题是如何从数组中获取实际值 Here h
  • Chart.js 时间序列跳过几天

    我有一个非常简单的条形图 其中每个数据点由日期 天 和数字组成 也许唯一的特点是并非涵盖每个日期 即有些日子没有数据点 绘制图表时 仅显示那些具有与其关联的数据点的日期 所有其他日期都被简单地省略 因此 x 轴分布不均匀并且会跳过值 如何确
  • 为什么用于 XML 文件分析的 PowerShell 工作流明显慢于非工作流脚本

    我正在编写一个 PowerShell 程序来分析 1900 多个大型 XML 配置文件 50000 多行 1 5Mb 的内容 为了进行测试 我将 36 个测试文件移动到我的 PC Win 10 PS 5 1 32GB RAM 并编写快速脚本
  • Microsoft(SQL)服务器许可[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我们正在规划一个浏览器应用程序 xbap 它将与 WCF 服务进行交互 这些 WCF 服务从 SQL 数据库获取信息 我们的每个客户在此服
  • 在 Visual Studio 中调试 x64 Azure Functions

    我正在通过 Visual Studio 编写 C Azure 函数 该函数通过博客存储触发 并且使用 x64 C DLL 处理 blob 问题是随 Visual Studio 安装的默认 Azure 函数工具仅具有 x86 版本的函数 ex
  • Fluent NHibernate join 不使用主键

    我试图从连接表中获取单个属性 其中主表中的非 PK 连接到外部表的 PK 下面是一个过于简单化我想要完成的事情的例子 我不想提及外国实体 Tables CREATE TABLE Status Id int Body text Categor
  • 我们可以将TFS 2015直接迁移到Azure DevOps吗?

    我计划转向 Azure DevOps 目前我们内部有 TFS2015 根据这篇文章 我们必须先迁移到 TFS 2018 然后才能迁移到 Azure DevOps 我们不能从 TFS 2015 迁移到 Azure DevOps 吗 根据本文
  • 依赖注入和命名记录器

    我有兴趣了解更多有关人们如何使用依赖注入平台注入日志记录的信息 尽管下面的链接和我的示例引用了 log4net 和 Unity 但我不一定会使用其中任何一个 对于依赖注入 IOC 我可能会使用 MEF 因为这是项目 大型 其余部分所采用的标
  • ValueError:无效端点:https://s3..amazonaws.com

    当 EMR 机器尝试运行包含 boto3 初始化的步骤时 有时会出现以下错误 ValueError Invalid endpoint https s3 amazonaws com当我尝试设置一台新机器时 它突然可以工作了 附上完整错误 se
  • 不兼容的库版本:imagick.so 需要版本 18.0.0 或更高版本,但 libfreetype.6.dylib 在第 0 行的 Unknown 中提供版本 16.0.0

    我成功安装了 imagemagic 和 imagick 使用http www php net manual en imagick installation php 94169 http www php net manual en imagi
  • to_json 在 Rails 中返回字符串而不是 json

    下面的代码应该返回一个 json series series map do serie name gt serie name id gt serie id series to json 其返回结果如下 name Barra id 3 nam
  • 什么是可以检测手写的好的 OCR? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我需要一个库 可以在扫描手写纸后从其中提取文本 正常拉丁文本 它可以是一个免费的解决方案 甚至是我必须付费的解决方案 只要它可以处理大写字
  • READ_PRIVILEGED_PHONE_STATE 权限错误

    我创建了一个应用程序来监控呼叫 传入和传出 并且在电话响铃期间 它会显示有关号码的详细信息 来电一切正常 但是当用户拨打电话时 应用程序崩溃并出现以下错误 05 14 23 14 36 376 1427 1475 W BroadcastQu
  • F#:检测正则表达式模式中的错误

    我是编程新手 F 是我的第一个 NET 语言 作为初学者的项目 我想编写一个应用程序 要求用户输入正则表达式模式 然后标记任何错误 我已经浏览了 MSDN 上的 Regex API 但似乎没有任何方法可以自动检测正则表达式模式中的任何错误
  • 如何进行这种图像转换?

    我有一个带有模糊边缘的彩色斑点的图像 上半部分 我想为其创建一个由直线组成的轮廓 下半部分 填充形状没有问题 只需添加轮廓即可 如有必要 可以将其转换为黑白图像 谁能指出一个可以做到这一点的简单转换 程序 最好是我可以轻松找到代码示例的东西