Mercurial > hg > orthanc
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 } |