comparison Core/Images/ImageProcessing.cpp @ 3258:6f652c7bfc85

ImageProcessing::FillPolygon
author Alain Mazy <alain@mazy.be>
date Mon, 18 Feb 2019 18:43:40 +0100
parents 3ca924140de6
children 6f9398eb902d
comparison
equal deleted inserted replaced
3257:5d1f998b0b18 3258:6f652c7bfc85
41 41
42 #include <cassert> 42 #include <cassert>
43 #include <string.h> 43 #include <string.h>
44 #include <limits> 44 #include <limits>
45 #include <stdint.h> 45 #include <stdint.h>
46 #include <algorithm>
46 47
47 namespace Orthanc 48 namespace Orthanc
48 { 49 {
49 template <typename TargetType, typename SourceType> 50 template <typename TargetType, typename SourceType>
50 static void ConvertInternal(ImageAccessor& target, 51 static void ConvertInternal(ImageAccessor& target,
1362 1363
1363 default: 1364 default:
1364 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 1365 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1365 } 1366 }
1366 } 1367 }
1368
1369 void ComputePolygonExtent(int32_t& left, int32_t& right, int32_t& top, int32_t& bottom, const std::vector<ImageProcessing::ImagePoint>& points)
1370 {
1371 left = std::numeric_limits<int32_t>::max();
1372 right = std::numeric_limits<int32_t>::min();
1373 top = std::numeric_limits<int32_t>::max();
1374 bottom = std::numeric_limits<int32_t>::min();
1375
1376 for (size_t i = 0; i < points.size(); i++)
1377 {
1378 const ImageProcessing::ImagePoint& p = points[i];
1379 left = std::min(p.GetX(), left);
1380 right = std::max(p.GetX(), right);
1381 bottom = std::max(p.GetY(), bottom);
1382 top = std::min(p.GetY(), top);
1383 }
1384 }
1385
1386 template <PixelFormat TargetFormat>
1387 void FillPolygon_(ImageAccessor& image,
1388 const std::vector<ImageProcessing::ImagePoint>& points,
1389 int64_t value_)
1390 {
1391 typedef typename PixelTraits<TargetFormat>::PixelType TargetType;
1392
1393 TargetType value = PixelTraits<TargetFormat>::IntegerToPixel(value_);
1394 int32_t left;
1395 int32_t right;
1396 int32_t top;
1397 int32_t bottom;
1398
1399 ComputePolygonExtent(left, right, top, bottom, points);
1400
1401 // from http://alienryderflex.com/polygon_fill/
1402
1403 // convert all "corner" points to double only once
1404 std::vector<double> cpx;
1405 std::vector<double> cpy;
1406 size_t cpSize = points.size();
1407 for (size_t i = 0; i < points.size(); i++)
1408 {
1409 cpx.push_back((double)points[i].GetX());
1410 cpy.push_back((double)points[i].GetY());
1411 }
1412
1413 std::vector<int32_t> nodeX;
1414 nodeX.resize(cpSize);
1415 int nodes, pixelX, pixelY, i, j, swap ;
1416
1417 // Loop through the rows of the image.
1418 for (pixelY = top; pixelY < bottom; pixelY++)
1419 {
1420 double y = (double)pixelY;
1421 // Build a list of nodes.
1422 nodes = 0;
1423 j = static_cast<int>(cpSize) - 1;
1424
1425 for (i = 0; i < cpSize; i++)
1426 {
1427 if ((cpy[i] < y && cpy[j] >= y) || (cpy[j] < y && cpy[i] >= y))
1428 {
1429 nodeX[nodes++] = (int32_t)(cpx[i] + (y - cpy[i])/(cpy[j] - cpy[i]) * (cpx[j] - cpx[i]));
1430 }
1431 j=i;
1432 }
1433
1434 // Sort the nodes, via a simple “Bubble” sort.
1435 i=0;
1436 while (i < nodes-1)
1437 {
1438 if (nodeX[i] > nodeX[i+1])
1439 {
1440 swap = nodeX[i];
1441 nodeX[i] = nodeX[i+1];
1442 nodeX[i+1] = swap;
1443 if (i > 0)
1444 {
1445 i--;
1446 }
1447 }
1448 else
1449 {
1450 i++;
1451 }
1452 }
1453
1454 TargetType* row = reinterpret_cast<TargetType*>(image.GetRow(pixelY));
1455 // Fill the pixels between node pairs.
1456 for (i=0; i<nodes; i+=2)
1457 {
1458 if (nodeX[i] >= right)
1459 break;
1460
1461 if (nodeX[i+1] >= left)
1462 {
1463 if (nodeX[i]< left)
1464 {
1465 nodeX[i] = left;
1466 }
1467
1468 if (nodeX[i+1] > right)
1469 {
1470 nodeX[i+1] = right;
1471 }
1472
1473 for (pixelX = nodeX[i]; pixelX <= nodeX[i+1]; pixelX++)
1474 {
1475 *(row + pixelX) = value;
1476 }
1477 }
1478 }
1479 }
1480 }
1481
1482 void ImageProcessing::FillPolygon(ImageAccessor& image,
1483 const std::vector<ImagePoint>& points,
1484 int64_t value)
1485 {
1486 switch (image.GetFormat())
1487 {
1488 case Orthanc::PixelFormat_Grayscale8:
1489 {
1490 FillPolygon_<Orthanc::PixelFormat_Grayscale8>(image, points, value);
1491 break;
1492 }
1493 case Orthanc::PixelFormat_Grayscale16:
1494 {
1495 FillPolygon_<Orthanc::PixelFormat_Grayscale16>(image, points, value);
1496 break;
1497 }
1498 case Orthanc::PixelFormat_SignedGrayscale16:
1499 {
1500 FillPolygon_<Orthanc::PixelFormat_SignedGrayscale16>(image, points, value);
1501 break;
1502 }
1503 default:
1504 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1505 }
1506 }
1507
1367 } 1508 }