Qt:提取由感兴趣区域多边形剪裁的强度值

Qt:提取由感兴趣区域多边形剪裁的强度值,qt,polygon,mask,Qt,Polygon,Mask,基于灰度图像和有序闭合多边形(可能是凹面),我希望获得位于感兴趣多边形区域内的所有灰度值(如中所述)。Qt4.8中最有效的实现是什么?端点应该是某种类型的QList。谢谢你的建议 此外,是否可以计算浮点掩码(例如,0表示多边形外部,0.3表示30%的像素区域位于多边形内部,1表示完全位于多边形内部)?然而,这只是一个额外的端点,然后将是QPair(百分比,值)。谢谢。首先需要扫描线将多边形转换为水平线——这是通过getScanLines()完成的。扫描线用于使用scanlineScanner()

基于灰度图像和有序闭合多边形(可能是凹面),我希望获得位于感兴趣多边形区域内的所有灰度值(如中所述)。Qt4.8中最有效的实现是什么?端点应该是某种类型的
QList
。谢谢你的建议


此外,是否可以计算浮点掩码(例如,0表示多边形外部,0.3表示30%的像素区域位于多边形内部,1表示完全位于多边形内部)?然而,这只是一个额外的端点,然后将是
QPair
(百分比,值)。谢谢。

首先需要扫描线将多边形转换为水平线——这是通过
getScanLines()
完成的。扫描线用于使用
scanlineScanner()
对图像进行采样,以获取每条线端点内的所有值

下面是一个完整的、独立的、可编译的示例,我展示了扫描线算法的良好性能。也可以调整它来计算定点遮罩。到目前为止,如果扫描线在水平范围内覆盖了超过一半的点(由于
scanlineScanner
中的
round()s
),则包括一个点

启动后,调整窗口大小并单击“周围”,以定义多边形中的连续点。您看到的多边形仅使用扫描线进行渲染。为了进行比较,可以启用多边形的轮廓

我相信扫描线转换器可以进一步优化。我没有做任何图像采样,但是
scanlineScanner
显示这是一件小事

// https://github.com/KubaO/stackoverflown/tree/master/questions/scanline-converter-11037252
#define QT_DISABLE_DEPRECATED_BEFORE 5
#include <QtGui>
#if QT_VERSION > QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
#include <algorithm>

typedef QVector<QPointF> PointVector;
typedef QVector<QLineF> LineVector;

// A list of vertex indices in the polygon, sorted ascending in their y coordinate
static QVector<int> sortedVertices(const QPolygonF & poly)
{
   Q_ASSERT(! poly.isEmpty());
   QVector<int> vertices;
   vertices.reserve(poly.size());
   for (int i = 0; i < poly.size(); ++i) { vertices << i; }
   std::sort(vertices.begin(), vertices.end(), [&](int i, int j){
      return poly[i].y() < poly[j].y();
   });
   return vertices;
}

// Returns point of intersection of infinite lines ref and target
static inline QPointF intersect(const QLineF & ref, const QLineF & target)
{
   QPointF p;
   target.intersect(ref, &p);
   return p;
}

// Allows accessing polygon vertices using an indirect index into a vector of indices.
class VertexAccessor {
   const QPolygonF & p;
   const QVector<int> & i;
public:
   VertexAccessor(const QPolygonF & poly, const QVector<int> & indices) :
      p(poly), i(indices) {}
   inline QPointF operator[](int ii) const {
      return p[i[ii]];
   }
   inline QPointF prev(int ii) const {
      int index = i[ii] - 1;
      if (index < 0) index += p.size();
      return p[index];
   }
   inline QPointF next(int ii) const {
      int index = i[ii] + 1;
      if (index >= p.size()) index -= p.size();
      return p[index];
   }
};

// Returns a horizontal line scanline rendering of an unconstrained polygon.
// The lines are generated on an integer grid, but this could be modified for any other grid.
static LineVector getScanlines(const QPolygonF & poly)
{
   LineVector lines;
   if (poly.isEmpty()) return lines;
   const QVector<int> indices = sortedVertices(poly);
   VertexAccessor vertex{poly, indices};
   const QRectF bound = poly.boundingRect();
   const auto l = bound.left();
   const auto r = bound.right();
   int ii = 0;
   int yi = qFloor(vertex[0].y());
   QList<int> active;
   PointVector points;
   forever {
      const qreal y = yi;
      const QLineF sweeper{l, y, r, y};
      // Remove vertex from the active list if both lines extending from it are above sweeper
      for (int i = 0; i < active.size(); ) {
         const int ii = active.at(i);
         // Remove vertex
         if (vertex.prev(ii).y() < y && vertex.next(ii).y() < y) {
            active.removeAt(i);
         } else {
            ++ i;
         }
      }
      // Add new vertices to the active list
      while (ii < poly.count() && vertex[ii].y() < y) {
         active << ii++;
      }
      if (ii >= poly.count() && active.isEmpty()) break;
      // Generate sorted intersection points
      points.clear();
      for (auto ii : active) {
         const auto a = vertex[ii];
         auto b = vertex.prev(ii);
         if (b.y() >= y)
            points << intersect(sweeper, QLineF{a, b});
         b = vertex.next(ii);
         if (b.y() >= y)
            points << intersect(sweeper, QLineF{a, b});
      }
      std::sort(points.begin(), points.end(), [](const QPointF & p1, const QPointF & p2){
         return p1.x() < p2.x();
      });
      // Generate horizontal fill segments
      for (int i = 0; i < points.size() - 1; i += 2) {
         lines << QLineF{points.at(i).x(), y, points.at(i+1).x(), y};
      }
      yi++;
   };
   return lines;
}

QVector<int> scanlineScanner(const QImage & image, const LineVector & tess)
{
   QVector<int> values;
   for (auto & line : tess) {
      for (int x = round(line.x1()); x <= round(line.x2()); ++ x) {
         values << qGray(image.pixel(x, line.y1()));
      }
   }
   return values;
}

class Ui : public QWidget
{
   Q_OBJECT
   QPointF lastPoint;
   QPolygonF polygon;
   LineVector scanlines;
   QGridLayout layout{this};
   QPushButton reset{"Reset"};
   QCheckBox outline{"Outline"};
public:
   Ui() {
      setMinimumSize(200, 200);
      layout.addItem(new QSpacerItem{0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding}, 0, 0, 1, 3);
      layout.addWidget(&reset, 1, 0);
      layout.addWidget(&outline, 1, 1);
      layout.addItem(new QSpacerItem{0, 0, QSizePolicy::Expanding}, 1, 2);
      reset.setObjectName("reset");
      outline.setObjectName("outline");
      QMetaObject::connectSlotsByName(this);
   }
protected:
   Q_SLOT void on_reset_clicked() {
      polygon.clear();
      scanlines.clear();
      lastPoint = QPointF{};
      update();
   }
   Q_SLOT void on_outline_stateChanged() {
      update();
   }
   void paintEvent(QPaintEvent *) override {
      QPainter p{this};
      if (false) p.setRenderHint(QPainter::Antialiasing);
      p.setPen("cadetblue");
      if (!polygon.isEmpty() && scanlines.isEmpty()) {
         scanlines = getScanlines(polygon);
         qDebug() << "new scanlines";
      }
      p.drawLines(scanlines);
      if (outline.isChecked()) {
         p.setPen("orangered");
         p.setBrush(Qt::NoBrush);
         p.drawPolygon(polygon);
      }
      if (!lastPoint.isNull()) {
         p.setPen("navy");
         p.drawEllipse(lastPoint, 3, 3);
      }
   }
   void mousePressEvent(QMouseEvent * ev) override {
      lastPoint = ev->posF();
      polygon << ev->posF();
      scanlines.clear();
      update();
   }
};

int main(int argc, char** argv)
{
   QApplication app{argc, argv};
   Ui ui;
   ui.show();
   return app.exec();
}

#include "main.moc"
//https://github.com/KubaO/stackoverflown/tree/master/questions/scanline-converter-11037252
#在5之前定义QT\u禁用\u已弃用\u
#包括
#如果QT_版本>QT_版本检查(5,0,0)
#包括
#恩迪夫
#包括
typedef-QVector-PointVector;
typedef-QVector-LineVector;
//多边形中顶点索引的列表,按y坐标升序排序
静态QVector分类广告(const QPolygonF&poly)
{
Q_断言(!poly.isEmpty());
矢量顶点;
顶点保留(poly.size());
对于(inti=0;i=y)
点数=y)
要点