comparison Core/Images/ImageProcessing.cpp @ 3502:c160eafc42a9

new functions in ImageProcessing toolbox: FlipX/Y(), Resize(), Halve()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 26 Aug 2019 10:23:51 +0200
parents d8f7c3970e25
children 46cf170ba121
comparison
equal deleted inserted replaced
3501:27b53c61aa99 3502:c160eafc42a9
32 32
33 33
34 #include "../PrecompiledHeaders.h" 34 #include "../PrecompiledHeaders.h"
35 #include "ImageProcessing.h" 35 #include "ImageProcessing.h"
36 36
37 #include "Image.h"
38 #include "ImageTraits.h"
37 #include "PixelTraits.h" 39 #include "PixelTraits.h"
38 #include "../OrthancException.h" 40 #include "../OrthancException.h"
39 41
40 #include <boost/math/special_functions/round.hpp> 42 #include <boost/math/special_functions/round.hpp>
41 43
1550 } 1552 }
1551 default: 1553 default:
1552 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 1554 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1553 } 1555 }
1554 } 1556 }
1557
1558
1559 template <PixelFormat Format>
1560 static void ResizeInternal(ImageAccessor& target,
1561 const ImageAccessor& source)
1562 {
1563 assert(target.GetFormat() == source.GetFormat() &&
1564 target.GetFormat() == Format);
1565
1566 const unsigned int sourceWidth = source.GetWidth();
1567 const unsigned int sourceHeight = source.GetHeight();
1568 const unsigned int targetWidth = target.GetWidth();
1569 const unsigned int targetHeight = target.GetHeight();
1570
1571 if (targetWidth == 0 || targetHeight == 0)
1572 {
1573 return;
1574 }
1575
1576 if (sourceWidth == 0 || sourceHeight == 0)
1577 {
1578 // Avoids division by zero below
1579 ImageProcessing::Set(target, 0);
1580 return;
1581 }
1582
1583 const float scaleX = static_cast<float>(sourceWidth) / static_cast<float>(targetWidth);
1584 const float scaleY = static_cast<float>(sourceHeight) / static_cast<float>(targetHeight);
1585
1586
1587 /**
1588 * Create two lookup tables to quickly know the (x,y) position
1589 * in the source image, given the (x,y) position in the target
1590 * image.
1591 **/
1592
1593 std::vector<unsigned int> lookupX(targetWidth);
1594
1595 for (unsigned int x = 0; x < targetWidth; x++)
1596 {
1597 int sourceX = std::floor((static_cast<float>(x) + 0.5f) * scaleX);
1598 if (sourceX < 0)
1599 {
1600 sourceX = 0; // Should never happen
1601 }
1602 else if (sourceX >= static_cast<int>(sourceWidth))
1603 {
1604 sourceX = sourceWidth - 1;
1605 }
1606
1607 lookupX[x] = static_cast<unsigned int>(sourceX);
1608 }
1609
1610 std::vector<unsigned int> lookupY(targetHeight);
1611
1612 for (unsigned int y = 0; y < targetHeight; y++)
1613 {
1614 int sourceY = std::floor((static_cast<float>(y) + 0.5f) * scaleY);
1615 if (sourceY < 0)
1616 {
1617 sourceY = 0; // Should never happen
1618 }
1619 else if (sourceY >= static_cast<int>(sourceHeight))
1620 {
1621 sourceY = sourceHeight - 1;
1622 }
1623
1624 lookupY[y] = static_cast<unsigned int>(sourceY);
1625 }
1626
1627
1628 /**
1629 * Actual resizing
1630 **/
1631
1632 for (unsigned int targetY = 0; targetY < targetHeight; targetY++)
1633 {
1634 unsigned int sourceY = lookupY[targetY];
1635
1636 for (unsigned int targetX = 0; targetX < targetWidth; targetX++)
1637 {
1638 unsigned int sourceX = lookupX[targetX];
1639
1640 typename ImageTraits<Format>::PixelType pixel;
1641 ImageTraits<Format>::GetPixel(pixel, source, sourceX, sourceY);
1642 ImageTraits<Format>::SetPixel(target, pixel, targetX, targetY);
1643 }
1644 }
1645 }
1646
1647
1648
1649 void ImageProcessing::Resize(ImageAccessor& target,
1650 const ImageAccessor& source)
1651 {
1652 if (source.GetFormat() != source.GetFormat())
1653 {
1654 throw OrthancException(ErrorCode_IncompatibleImageFormat);
1655 }
1656
1657 if (source.GetWidth() == target.GetWidth() &&
1658 source.GetHeight() == target.GetHeight())
1659 {
1660 Copy(target, source);
1661 return;
1662 }
1663
1664 switch (source.GetFormat())
1665 {
1666 case PixelFormat_Grayscale8:
1667 ResizeInternal<PixelFormat_Grayscale8>(target, source);
1668 break;
1669
1670 case PixelFormat_RGB24:
1671 ResizeInternal<PixelFormat_RGB24>(target, source);
1672 break;
1673
1674 default:
1675 throw OrthancException(ErrorCode_NotImplemented);
1676 }
1677 }
1678
1679
1680 ImageAccessor* ImageProcessing::Halve(const ImageAccessor& source,
1681 bool forceMinimalPitch)
1682 {
1683 std::auto_ptr<Image> target(new Image(source.GetFormat(), source.GetWidth() / 2,
1684 source.GetHeight() / 2, forceMinimalPitch));
1685 Resize(*target, source);
1686 return target.release();
1687 }
1688
1689
1690 template <PixelFormat Format>
1691 static void FlipXInternal(ImageAccessor& image)
1692 {
1693 const unsigned int height = image.GetHeight();
1694 const unsigned int width = image.GetWidth();
1695
1696 for (unsigned int y = 0; y < height; y++)
1697 {
1698 for (unsigned int x1 = 0; x1 < width / 2; x1++)
1699 {
1700 unsigned int x2 = width - 1 - x1;
1701
1702 typename ImageTraits<Format>::PixelType a, b;
1703 ImageTraits<Format>::GetPixel(a, image, x1, y);
1704 ImageTraits<Format>::GetPixel(b, image, x2, y);
1705 ImageTraits<Format>::SetPixel(image, a, x2, y);
1706 ImageTraits<Format>::SetPixel(image, b, x1, y);
1707 }
1708 }
1709 }
1710
1711
1712 void ImageProcessing::FlipX(ImageAccessor& image)
1713 {
1714 switch (image.GetFormat())
1715 {
1716 case PixelFormat_Grayscale8:
1717 FlipXInternal<PixelFormat_Grayscale8>(image);
1718 break;
1719
1720 case PixelFormat_RGB24:
1721 FlipXInternal<PixelFormat_RGB24>(image);
1722 break;
1723
1724 default:
1725 throw OrthancException(ErrorCode_NotImplemented);
1726 }
1727 }
1728
1729
1730 template <PixelFormat Format>
1731 static void FlipYInternal(ImageAccessor& image)
1732 {
1733 const unsigned int height = image.GetHeight();
1734 const unsigned int width = image.GetWidth();
1735
1736 for (unsigned int y1 = 0; y1 < height / 2; y1++)
1737 {
1738 unsigned int y2 = height - 1 - y1;
1739
1740 for (unsigned int x = 0; x < width; x++)
1741 {
1742 typename ImageTraits<Format>::PixelType a, b;
1743 ImageTraits<Format>::GetPixel(a, image, x, y1);
1744 ImageTraits<Format>::GetPixel(b, image, x, y2);
1745 ImageTraits<Format>::SetPixel(image, a, x, y2);
1746 ImageTraits<Format>::SetPixel(image, b, x, y1);
1747 }
1748 }
1749 }
1750
1751
1752 void ImageProcessing::FlipY(ImageAccessor& image)
1753 {
1754 switch (image.GetFormat())
1755 {
1756 case PixelFormat_Grayscale8:
1757 FlipYInternal<PixelFormat_Grayscale8>(image);
1758 break;
1759
1760 case PixelFormat_RGB24:
1761 FlipYInternal<PixelFormat_RGB24>(image);
1762 break;
1763
1764 default:
1765 throw OrthancException(ErrorCode_NotImplemented);
1766 }
1767 }
1555 } 1768 }