如何使用代码自动从背景中隔离艺术线条.有办法吗? [英] How to automate isolating line art from the background with code. Is there a way?

查看:157
本文介绍了如何使用代码自动从背景中隔离艺术线条.有办法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这就是我喜欢使用代码的方式. Photoshop在此过程中没有手动完成任何操作,所以我认为有办法吗?但不能完全弄清楚.

This is what I like to do with code. Nothing is manually done in the process with Photoshop, so I think there is a way? but can't quite figure it out.

这是我在Python中所做的:

This is what I did in Python:

from PIL import Image
im_rgb = Image.open('lena.jpg')
im_a = Image.open('frame.png').convert('L').resize(im_rgb.size)
im_rgba = im_rgb.copy()
im_rgba.putalpha(im_a)
im_rgba.save('final.png')

但是我正在寻找Android Studio上的Java/Kotlin解决方案,同时我也可以使用Dart或C ++中的示例.

but I'm looking for a solution in Java/Kotlin on Android Studio while I could live with a sample in Dart or C++ as well.

推荐答案

我从 了解到OP所描述的内容GIMP (在这里称为 颜色为Alpha .

当我不时使用该命令时,我试图想象如何实现它.

While I used that command from time to time I tried to imagine how this could be implemented.

我想到了多种方法:

  • 一个非常简单的方法:将每个像素与轴心颜色进行比较,并在匹配的情况下将alpha设置为0
  • 基于阈值的:确定像素的欧几里德距离以在RGB空间中旋转颜色(作为3D空间),并在给定阈值以下时根据距离设置Alpha
  • 基于阈值的HSV空间:与上面类似的方法,但适用于HSV空间(以实现更好的色彩匹配).
  • a very simple: compare every pixel with a pivot color and set alpha to 0 in case of match
  • a threshold-based: determine the Euclidean distance of pixel to pivot color in RGB space (as 3D space) and set alpha according to distance when under a given threshold
  • threshold-based in HSV space: the similar approach like above but applied to HSV space (for better color matching).

出于好奇,我编写了一个示例应用程序来进行尝试.

Out of curiosity, I wrote a sample application to try this out.

首先是用于将颜色转换为alpha的C ++代码:

First a C++ code for color to alpha transformation:

imageColorToAlpha.h:

#ifndef IMAGE_COLOR_TO_ALPHA_H
#define IMAGE_COLOR_TO_ALPHA_H

// standard C++ header:
#include <cstdint>
#include <functional>

// convenience types
typedef std::uint32_t Pixel;
typedef std::uint8_t Comp;

// convenience constants
const int ShiftR = 16;
const int ShiftG = 8;
const int ShiftB = 0;
const int ShiftA = 24;

const Pixel MaskR = 0xff << ShiftR;
const Pixel MaskG = 0xff << ShiftG;
const Pixel MaskB = 0xff << ShiftB;
const Pixel MaskA = 0xff << ShiftA;

const Pixel MaskRGB = MaskR | MaskG | MaskB;

// convenience functions
inline Comp getR(Pixel pixel) { return Comp(pixel >> ShiftR); }
inline Comp getG(Pixel pixel) { return Comp(pixel >> ShiftG); }
inline Comp getB(Pixel pixel) { return Comp(pixel >> ShiftB); }
inline Comp getA(Pixel pixel) { return Comp(pixel >> ShiftA); }

inline void setR(Pixel &pixel, Comp r)
{
  pixel &= ~MaskR;
  pixel |= r << ShiftR;
}
inline void setG(Pixel &pixel, Comp g)
{
  pixel &= ~MaskG;
  pixel |= g << ShiftG;
}
inline void setB(Pixel &pixel, Comp b)
{
  pixel &= ~MaskB;
  pixel |= b << ShiftB;
}
inline void setA(Pixel &pixel, Comp r)
{
  pixel &= ~MaskA;
  pixel |= r << ShiftA;
}
inline void set(Pixel &pixel, Comp r, Comp g, Comp b)
{
  pixel &= ~MaskRGB;
  pixel |= r << ShiftR | g << ShiftG | b << ShiftB;
}
inline void set(Pixel &pixel, Comp r, Comp g, Comp b, Comp a)
{
  pixel = r << ShiftR | g << ShiftG | b << ShiftB | a << ShiftA;
}

extern void transformImage(
  size_t w, size_t h, // width and height
  size_t bytesPerRow, // bytes per row (to handle row alignment)
  const Pixel *imgSrc, // source image
  Pixel *imgDst, // destination image
  std::function<Pixel(Pixel)> transform);

// color to alpha (very simple)
extern Pixel colorToAlpha(Pixel pixel, Pixel color);

// color to alpha (with threshold)
extern Pixel colorToAlpha(
  Pixel pixel, Pixel color, unsigned threshold);

// convenience functions for image

inline void colorToAlphaSimple(
  size_t w, size_t h, // width and height
  size_t bytesPerRow, // bytes per row (to handle row alignment)
  const Pixel *imgSrc, // source image
  Pixel *imgDst, // destination image
  Pixel color) // pivot color
{
  transformImage(w, h, bytesPerRow, imgSrc, imgDst,
    [color](Pixel pixel) { return colorToAlpha(pixel, color); });
}

inline void colorToAlphaThreshold(
  size_t w, size_t h, // width and height
  size_t bytesPerRow, // bytes per row (to handle row alignment)
  const Pixel *imgSrc, // source image
  Pixel *imgDst, // destination image
  Pixel color, // pivot color
  unsigned threshold) // threshold
{
  transformImage(w, h, bytesPerRow, imgSrc, imgDst,
    [color, threshold](Pixel pixel) {
      return colorToAlpha(pixel, color, threshold);
    });
}

inline void fillRGB(
  size_t w, size_t h, // width and height
  size_t bytesPerRow, // bytes per row (to handle row alignment)
  Pixel *img, // image to modify
  Pixel color) // fill color (alpha ignored)
{
  color &= MaskRGB;
  transformImage(w, h, bytesPerRow, img, img,
    [color](Pixel pixel) {
      pixel &= ~MaskRGB; pixel |= color; return pixel;
    });
}

#endif // IMAGE_COLOR_TO_ALPHA_H

和相应的imageColorToAlpha.cc:

// standard C++ header:
#include <cmath>

// header of this module:
#include "imageColorToAlpha.h"

void transformImage(
  size_t w, size_t h, // width and height
  size_t bytesPerRow, // bytes per row (to handle row alignment)
  const Pixel *imgSrc, // source image
  Pixel *imgDst, // destination image
  std::function<Pixel(Pixel)> transform)
{
  for (size_t y = 0; y < h; ++y) {
    const Pixel *pixelSrc = (const Pixel*)((const Comp*)imgSrc + y * bytesPerRow);
    Pixel *pixelDst = (Pixel*)((Comp*)imgDst + y * bytesPerRow);
    for (size_t x = 0; x < w; ++x) pixelDst[x] = transform(pixelSrc[x]);
  }
}

Pixel colorToAlpha(Pixel pixel, Pixel color)
{
  // eliminate current alpha values from pixel and color
  pixel &= MaskRGB; color &= MaskRGB;
  // compare pixel with color
  const int match = pixel == color;
  // set alpha according to match of pixel and color
  setA(pixel, ~(match * 0xff));
  // done
  return pixel;
}

Pixel colorToAlpha(Pixel pixel, Pixel color, unsigned threshold)
{
  // delta values per component
  const int dR = (int)getR(pixel) - (int)getR(color);
  const int dG = (int)getG(pixel) - (int)getG(color);
  const int dB = (int)getB(pixel) - (int)getB(color);
  // square Euclidean distance
  const unsigned dSqr = dR * dR + dG * dG + dB * dB;
  // compute alpha
  Comp a = 0xff;
  if (dSqr < threshold * threshold) { // distance below threshold?
    // compute alpha weighted by distance
    const double d = sqrt((double)dSqr);
    const double f = d / threshold;
    a = (Comp)(f * 0xff);
  }
  // done
  setA(pixel, a);
  return pixel;
}

此图像处理代码仅基于C ++ std库. 这旨在使代码尽可能地具有示范性和可重用性.

This image manipulation code is based on the C++ std library only. This is intended to make the code as exemplary and re-usable as possible.

但是,用于解码图像文件格式的代码通常既不简短也不简单. 因此,我在 Qt 中编写了一个包装器应用程序在行动中展示这一点. Qt提供了图像支持以及用于桌面应用程序的框架,在我看来,Qt最适合此任务(除了我对此有一定的经验之外).

However, the code for decoding image file formats is often neither short nor simple. Hence, I wrote a wrapper application in Qt to show this in action. Qt provides image support as well as the frame work for a desktop application and seemed to me as most appropriate for this task (beside of the fact that I've some experience with it).

Qt包装器应用程序testQImageColorToAlpha.cc:

The Qt wrapper application testQImageColorToAlpha.cc:

// Qt header:
#include <QtWidgets>

// own header:
#include "imageColorToAlpha.h"
#include "qColorButton.h"

// convenience functions
QPixmap fromImage(const QImage &qImg)
{
  QPixmap qPixmap;
  qPixmap.convertFromImage(qImg);
  return qPixmap;
}

QPixmap fromAlphaImage(
  const QImage &qImg,
  QColor qColor1 = Qt::darkGray,
  QColor qColor2 = Qt::gray,
  int whCell = 32)
{
  QPixmap qPixmap(qImg.width(), qImg.height());
  { QPainter qPainter(&qPixmap);
    // draw chessboard
    qPixmap.fill(qColor1);
    for (int y = 0; y < qImg.height(); y += 2 * whCell) {
      for (int x = 0; x < qImg.width(); x += 2 * whCell) {
        qPainter.fillRect(x, y, whCell, whCell, qColor2);
        qPainter.fillRect(x + whCell, y + whCell, whCell, whCell, qColor2);
      }
    }
    // overlay with image
    qPainter.drawImage(0, 0, qImg);
  } // close Qt painter
  // done
  return qPixmap;
}

enum {
  SingleValue,
  RGBRange
};

QImage colorToAlphaSimple(
  const QImage &qImgSrc, QColor qColor,
  bool fill, QColor qColorFill)
{
  // ensure expected format for input image
  QImage qImg = qImgSrc.convertToFormat(QImage::Format_ARGB32);
  const int w = qImg.width(), h = qImg.height(), bpr = qImg.bytesPerLine();
  // allocate storage for output image
  QImage qImgDst(w, h, QImage::Format_ARGB32);
  colorToAlphaSimple(w, h, bpr,
    (const Pixel*)qImg.constBits(), (Pixel*)qImgDst.bits(), qColor.rgba());
  // override RGB if required
  if (fill) fillRGB(w, h, bpr, (Pixel*)qImgDst.bits(), qColorFill.rgba());
  // done
  return qImgDst;
}

QImage colorToAlphaThreshold(
  const QImage &qImgSrc, QColor qColor, unsigned threshold,
  bool fill, QColor qColorFill)
{
  // ensure expected format for input image
  QImage qImg = qImgSrc.convertToFormat(QImage::Format_ARGB32);
  const int w = qImg.width(), h = qImg.height(), bpr = qImg.bytesPerLine();
  // allocate storage for output image
  QImage qImgDst(w, h, QImage::Format_ARGB32);
  colorToAlphaThreshold(w, h, bpr,
    (const Pixel*)qImg.constBits(), (Pixel*)qImgDst.bits(), qColor.rgba(), threshold);
  // override RGB if required
  if (fill) fillRGB(w, h, bpr, (Pixel*)qImgDst.bits(), qColorFill.rgba());
  // done
  return qImgDst;
}

// main application
int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // setup data
  QImage qImgIn("cat.drawn.png");
  QImage qImgOut(qImgIn);
  // setup GUI
  // main window
  QWidget qWin;
  qWin.setWindowTitle(QString::fromUtf8("Color to Alpha"));
  QGridLayout qGrid;
  // input image
  QHBoxLayout qHBoxLblIn;
  QLabel qLblIn(QString::fromUtf8("Input Image:"));
  qHBoxLblIn.addWidget(&qLblIn);
  qHBoxLblIn.addStretch(1);
  QPushButton qBtnLoad(QString::fromUtf8("Open..."));
  qHBoxLblIn.addWidget(&qBtnLoad);
  qGrid.addLayout(&qHBoxLblIn, 0, 0);
  QLabel qLblImgIn;
  qLblImgIn.setPixmap(fromImage(qImgIn));
  qGrid.addWidget(&qLblImgIn, 1, 0);
  // config. color to alpha
  QGroupBox qBoxCfg(QString::fromUtf8("Configuration:"));
  QFormLayout qFormCfg;
  QComboBox qMenuColorToAlpha;
  qMenuColorToAlpha.addItem(QString::fromUtf8("Single Value"));
  qMenuColorToAlpha.addItem(QString::fromUtf8("With Threshold"));
  qFormCfg.addRow(QString::fromUtf8("Color to Transparency:"), &qMenuColorToAlpha);
  QColorButton qBtnColor(Qt::white);
  qFormCfg.addRow(QString::fromUtf8("Pivot Color:"), &qBtnColor);
  qBoxCfg.setLayout(&qFormCfg);
  QSpinBox qEditRange;
  qEditRange.setRange(1, 255);
  qFormCfg.addRow(QString::fromUtf8("Range:"), &qEditRange);
  QFrame qHSepCfg;
  qHSepCfg.setFrameStyle(QFrame::HLine | QFrame::Plain);
  qFormCfg.addRow(&qHSepCfg);
  QHBoxLayout qHBoxFill;
  QCheckBox qTglFill;
  qTglFill.setChecked(false);
  qHBoxFill.addWidget(&qTglFill);
  QColorButton qBtnColorFill(Qt::black);
  qHBoxFill.addWidget(&qBtnColorFill, 1);
  qFormCfg.addRow(QString::fromUtf8("Fill Color:"), &qHBoxFill);
  qGrid.addWidget(&qBoxCfg, 1, 1);
  // output image
  QHBoxLayout qHBoxLblOut;
  QLabel qLblOut(QString::fromUtf8("Output Image:"));
  qHBoxLblOut.addWidget(&qLblOut);
  qHBoxLblOut.addStretch(1);
  QColorButton qBtnBgColor1(QString::fromUtf8("Color 1"), Qt::darkGray);
  qHBoxLblOut.addWidget(&qBtnBgColor1);
  QColorButton qBtnBgColor2(QString::fromUtf8("Color 2"), Qt::gray);
  qHBoxLblOut.addWidget(&qBtnBgColor2);
  qGrid.addLayout(&qHBoxLblOut, 0, 2);
  QLabel qLblImgOut;
  qLblImgOut.setPixmap(fromAlphaImage(qImgOut));
  qGrid.addWidget(&qLblImgOut, 1, 2);
  // main window
  qWin.setLayout(&qGrid);
  qWin.show();
  // helper
  auto update = [&]() {
    const int algo = qMenuColorToAlpha.currentIndex();
    switch (algo) {
      case SingleValue:
        qImgOut
          = colorToAlphaSimple(qImgIn, qBtnColor.color(),
            qTglFill.isChecked(), qBtnColorFill.color());
        break;
      case RGBRange:
        qImgOut
          = colorToAlphaThreshold(qImgIn, qBtnColor.color(), qEditRange.value(),
            qTglFill.isChecked(), qBtnColorFill.color());
        break;
    }
    qEditRange.setEnabled(algo >= RGBRange);
    qBtnColorFill.setEnabled(qTglFill.isChecked());
    qLblImgOut.setPixmap(
      fromAlphaImage(qImgOut, qBtnBgColor1.color(), qBtnBgColor2.color()));
  };
  // install signal handlers
  QObject::connect(
    &qBtnLoad, &QPushButton::clicked,
    [&]() {
      QString filePath
        = QFileDialog::getOpenFileName(
          &qWin, QString::fromUtf8("Open Image File"),
          QString(),
          QString::fromUtf8(
            "Image Files (*.png *.jpg *.jpeg);;"
            "PNG Files (*.png);;"
            "JPEG Files (*.jpg *.jpeg);;"
            "All Files (*)"));
      if (filePath.isEmpty()) return; // choice aborted
      QImage qImg;
      qImg.load(filePath);
      if (qImg.isNull()) return; // file loading failed
      qImgIn = qImg;
      qLblImgIn.setPixmap(fromImage(qImgIn));
      update();
    });
  QObject::connect(
    &qMenuColorToAlpha,
    QOverload<int>::of(&QComboBox::currentIndexChanged),
    [&](int) { update(); });
  QObject::connect(&qBtnColor, &QPushButton::clicked,
    [&]() { qBtnColor.chooseColor(); update(); });
  QObject::connect(
    &qEditRange, QOverload<int>::of(&QSpinBox::valueChanged),
    [&](int) { update(); });
  QObject::connect(&qTglFill, &QCheckBox::toggled,
    [&](bool) { update(); });
  QObject::connect(&qBtnColorFill, &QPushButton::clicked,
    [&]() { qBtnColorFill.chooseColor(); update(); });
  QObject::connect(&qBtnBgColor1, &QPushButton::clicked,
    [&]() { qBtnBgColor1.chooseColor(); update(); });
  QObject::connect(&qBtnBgColor2, &QPushButton::clicked,
    [&]() { qBtnBgColor2.chooseColor(); update(); });
  // runtime loop
  update();
  return app.exec();
}

和帮助程序类qColorButton.h:

// borrowed from https://stackoverflow.com/a/55889624/7478597

#ifndef Q_COLOR_BUTTON_H
#define Q_COLOR_BUTTON_H

// Qt header:
#include <QColorDialog>
#include <QPushButton>

// a Qt push button for color selection
class QColorButton: public QPushButton {
  private:
    QColor _qColor;

  public:
    explicit QColorButton(
      const QString &text = QString(), const QColor &qColor = Qt::black,
      QWidget *pQParent = nullptr):
      QPushButton(text, pQParent)
    {
      setColor(qColor);
    }
    explicit QColorButton(
      const QColor &qColor = Qt::black,
      QWidget *pQParent = nullptr):
      QColorButton(QString(), qColor, pQParent)
    { }
    virtual ~QColorButton() = default;

    QColorButton(const QColorButton&) = delete;
    QColorButton& operator=(const QColorButton&) = delete;

    const QColor& color() const { return _qColor; }
    void setColor(const QColor &qColor)
    {
      _qColor = qColor;
      QFontMetrics qFontMetrics(font());
      const int h = qFontMetrics.height();
      QPixmap qPixmap(h, h);
      qPixmap.fill(_qColor);
      setIcon(qPixmap);
    }

    QColor chooseColor()
    {
      setColor(QColorDialog::getColor(_qColor, this, text()));
      return _qColor;
    }
};

#endif // Q_COLOR_BUTTON_H

启动时,将加载默认图像并应用简单匹配:

When started, a default image is loaded and the simple matching is applied:

我从 jloog.com/images/<下载了示例图片/a>.

I downloaded the sample image from jloog.com/images/.

结果看起来有点差. 白色背景是匹配的,但在黑色绘图周围会出现白色伪影. 这是由采样导致的,其中覆盖图形和背景的像素分别灰色阴影.

The result looks a bit poor. The white background is matched but there appear white artefacts around black drawing. This results from sampling where pixels which covered the drawing as well as the background got respective shades of gray.

因此,更好的方法是将枢轴颜色的距离转换为相应的alpha值,从而阈值定义了范围以及应该考虑颜色的范围:

So, a better approach is to turn the distance from pivot color into a respective alpha value whereby the threshold defines the range as well as a limit upto that colors shall be considered:

那看起来更好.

现在,我很好奇这在真实"环境下的效果如何照片:

Now, I became curious how well this works in “real” photos:

当我害怕的时候结果会更好.

The result is better when I was afraid.

但是,它显示了我到目前为止所采用方法的局限性.

However, it shows the limits of the approach I got so far.

更新:

虽然我正在研究网络以获得从RGB到HSV的精确转换,但我学到了很多关于不同的 色差 ,在其中我发现了一些有趣的陈述:

While I was researching the web to get the precise conversion from RGB to HSV, I learnt a lot about the different HSL and HSV models I was not aware of before. Finally, I stumbled into Color difference where I found some interesting statements:

由于大多数色差的定义是颜色空间内的距离,因此确定距离的标准方法是欧几里得距离.如果当前有一个RGB(红色,绿色,蓝色)元组并希望找到色差,则计算上最简单的方法之一就是调用R,G,B定义颜色空间的线性尺寸.

As most definitions of color difference are distances within a color space, the standard means of determining distances is the Euclidean distance. If one presently has an RGB (Red, Green, Blue) tuple and wishes to find the color difference, computationally one of the easiest is to call R, G, B linear dimensions defining the color space.

有许多颜色距离公式尝试使用色相为圆形的HSV等颜色空间,将各种颜色放置在圆柱体或圆锥体的三维空间中,但其中大多数只是对颜色的修改. RGB;如果不考虑人类对颜色的感知差异,它们将倾向于与简单的欧几里德度量标准相提并论.

There are a number of color distance formulae that attempt to use color spaces like HSV with the hue as a circle, placing the various colors within a three dimensional space of either a cylinder or cone, but most of these are just modifications of RGB; without accounting for differences in human color perception they will tend to be on par with a simple Euclidean metric.

因此,我放弃了在HSV空间进行匹配的想法.

So, I discarded the idea with matching in HSV space.

相反,我做了一个非常简单的扩展,恕我直言,它对单色绘图提供了重大改进:

Instead, I made a very simple extension which IMHO provides a significant improvement concerning monochrom drawings:

具有混合图形和背景的像素被转换为alpha阴影,但RGB值保持不变. 这不是很正确,因为它实际上应该变成与Alpha混合的前景色(铅笔色). 为了解决这个问题,我添加了一个选项,用一种选择的颜色覆盖输出的RGB值.

The pixels with mixed drawing and background are transformed into shades of alpha but the RGB values are left untouched. This is not quite correct because it should actually become the foreground color (pencil color) blended with alpha. To fix this, I added an option to override the RGB values of the output with a color of choice.

这是颜色被覆盖的结果:

This is the result with overridden color:

顺便说一句.它会带来一些不错的额外效果–铅笔的颜色可以修改:

Btw. it allows a nice little extra effect – the pencil color can be modified:

(以上示例源代码已更新,以反映最近的更改.)

(The above sample source code has been updated to reflect the last changes.)

要构建示例,可以将任一CMake与此CMakeLists.txt一起使用:

To build the sample, either CMake can be used with this CMakeLists.txt:

project(QImageColorToAlpha)

cmake_minimum_required(VERSION 3.10.0)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)
#set(CMAKE_CXX_STANDARD 17)
#set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

find_package(Qt5Widgets CONFIG REQUIRED)

include_directories(
  "${CMAKE_SOURCE_DIR}")

add_executable(testQImageColorToAlpha
  testQImageColorToAlpha.cc
  qColorButton.h # qColorButton.cc
  imageColorToAlpha.h imageColorToAlpha.cc)

target_link_libraries(testQImageColorToAlpha
  Qt5::Widgets)

# define QT_NO_KEYWORDS to prevent confusion between of Qt signal-slots and
# other signal-slot APIs
target_compile_definitions(testQImageColorToAlpha PUBLIC QT_NO_KEYWORDS)

我曾经在VS2017中构建它.

which I used to build it in VS2017.

或者,最小的Qt项目文件testQImageColorToAlpha.pro:

Alternatively, a minimal Qt project file testQImageColorToAlpha.pro:

SOURCES = testQImageColorToAlpha.cc imageColorToAlpha.cc

QT += widgets

我在 cygwin 中测试的

:

which I tested in cygwin:

$ qmake-qt5 testQImageColorToAlpha.pro 

$ make && ./testQImageColorToAlpha
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQImageColorToAlpha.o testQImageColorToAlpha.cc
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o imageColorToAlpha.o imageColorToAlpha.cc
g++  -o testQImageColorToAlpha.exe testQImageColorToAlpha.o imageColorToAlpha.o   -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread 
Qt Version: 5.9.4

这篇关于如何使用代码自动从背景中隔离艺术线条.有办法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆