diff --git a/CMakeLists.txt b/CMakeLists.txt
index 60ed627..7e5bf34 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -108,6 +108,7 @@ set(MRASTER_INCLUDES "lib/MRcolor.hpp"
"lib/hersheyFont.hpp"
"lib/MRpoint2d.hpp"
"lib/ramCanvas.hpp"
+ "lib/ramCanvasPixelFilters.hpp"
"lib/ramCanvasTpl.hpp")
add_library(MRaster INTERFACE ${MRASTER_INCLUDES})
target_include_directories(MRaster INTERFACE "${PROJECT_SOURCE_DIR}/lib")
diff --git a/docs/roadmap.html b/docs/roadmap.html
index 5840f34..57cb4ad 100644
--- a/docs/roadmap.html
+++ b/docs/roadmap.html
@@ -3,7 +3,7 @@
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
+
MRaster Roadmap
@@ -278,6 +278,7 @@ MRaster Roadmap
+- Use callables for pixel transforms
- Homo transforms
Complex abs/arg greyscale transform DONE.
diff --git a/docs/roadmap.org b/docs/roadmap.org
index 84d0fe5..d1cc6a8 100644
--- a/docs/roadmap.org
+++ b/docs/roadmap.org
@@ -40,6 +40,7 @@ end up on this list.
In no particular order:
+ - Use callables for pixel transforms
- Homo transforms
- +Complex abs/arg greyscale transform+ DONE.
- +2D plane Color Schemes+ DONE
diff --git a/examples/convertRawToTIFF.cpp b/examples/convertRawToTIFF.cpp
index 88b0d1d..9e301d9 100644
--- a/examples/convertRawToTIFF.cpp
+++ b/examples/convertRawToTIFF.cpp
@@ -53,16 +53,16 @@ int main(int argc, char *argv[]) {
// We create a converter object for the *two* file write methods below. This converter will transform the 32-bit floating point channels into 8-bit
// unsigned integer channels.
- mjr::ramCanvas3c32F::rcConverterRGBbyte rcConv(theRamCanvas);
+ mjr::ramCanvasPixelFilter::RGBbyte pxFilt(theRamCanvas);
- ret = theRamCanvas.writeRAWfile("foo.mrw", rcConv);
+ ret = theRamCanvas.writeRAWfile("foo.mrw", pxFilt);
if (ret != 0) {
std::cout << "ERROR(writeRAWfile): " << ret << std::endl;
return ret;
}
// Note: For the more complex writeTIFFfile() method, the markAlpha argument is not optional.
- ret = theRamCanvas.writeTIFFfile("foo.tiff", rcConv, false);
+ ret = theRamCanvas.writeTIFFfile("foo.tiff", pxFilt);
if (ret != 0) {
std::cout << "ERROR(writeTIFFfile): " << ret << std::endl;
return ret;
diff --git a/examples/newton_orbits.cpp b/examples/newton_orbits.cpp
index 4f51ab0..173c3aa 100644
--- a/examples/newton_orbits.cpp
+++ b/examples/newton_orbits.cpp
@@ -34,15 +34,12 @@
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
#include "ramCanvas.hpp"
-//--------------------------------------------------------------------------------------------------------------------------------------------------------------
-typedef mjr::ramCanvas1c16b::rcConverterMonoIntensity g2mono;
-
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
int main(void) {
std::chrono::time_point startTime = std::chrono::system_clock::now();
constexpr int MaxCount = 255;
constexpr double Tol = .0001;
- constexpr int IMGSIZ = 7680;
+ constexpr int IMGSIZ = 7680/4;
std::complex r1( 1.0, 0.0);
std::complex r2(-0.5, sin(2*std::numbers::pi/3));
std::complex r3(-0.5, -sin(2*std::numbers::pi/3));
@@ -59,15 +56,15 @@ int main(void) {
count++;
}
- mjr::ramCanvas3c16b::colorType cDelta;
+ decltype(theRamCanvas)::colorType cDelta;
if(abs(z-r1) <= Tol)
- cDelta = mjr::ramCanvas3c16b::colorType(1, 0, 0);
+ cDelta = decltype(theRamCanvas)::colorType(1, 0, 0);
else if(abs(z-r2) <= Tol)
- cDelta = mjr::ramCanvas3c16b::colorType(0, 1, 0);
+ cDelta = decltype(theRamCanvas)::colorType(0, 1, 0);
else if(abs(z-r3) <= Tol)
- cDelta = mjr::ramCanvas3c16b::colorType(0, 0, 1);
+ cDelta = decltype(theRamCanvas)::colorType(0, 0, 1);
else
- cDelta = mjr::ramCanvas3c16b::colorType(0, 0, 0);
+ cDelta = decltype(theRamCanvas)::colorType(0, 0, 0);
for(int i=0; i(theRamCanvas);
+ auto tf2 = mjr::ramCanvasPixelFilter::Rotate90CW(tf1);
+ theRamCanvas.writeTIFFfile("newton_orbits_mon.tiff", tf2);
std::chrono::duration runTime = std::chrono::system_clock::now() - startTime;
std::cout << "Total Runtime " << runTime.count() << " sec" << std::endl;
diff --git a/examples/peterdejongEAAO.cpp b/examples/peterdejongEAAO.cpp
index c61c44a..2b04f6e 100644
--- a/examples/peterdejongEAAO.cpp
+++ b/examples/peterdejongEAAO.cpp
@@ -51,8 +51,8 @@
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
int main(void) {
std::chrono::time_point startTime = std::chrono::system_clock::now();
- const int IMXSIZ = 7680/1;
- const int IMYSIZ = 7680/1;
+ const int IMXSIZ = 7680/4;
+ const int IMYSIZ = 7680/4;
const int n = 8;
const double a = 1.4;
@@ -112,14 +112,10 @@ int main(void) {
p4canvas.drawPoint(xi, yi, decltype(p1canvas)::colorType::csCColdeFireRamp::c(r*r));
}
}
- p1canvas.scaleDownMean(4);
- p2canvas.scaleDownMean(4);
- p3canvas.scaleDownMean(4);
- p4canvas.scaleDownMean(4);
- p1canvas.writeTIFFfile("peterdejongEAAO_00_c1.tiff");
- p2canvas.writeTIFFfile("peterdejongEAAO_00_c2.tiff");
- p3canvas.writeTIFFfile("peterdejongEAAO_00_c3.tiff");
- p4canvas.writeTIFFfile("peterdejongEAAO_00_c4.tiff");
+ p1canvas.writeTIFFfile("peterdejongEAAO_00_c1.tiff", mjr::ramCanvasPixelFilter::ScaleDownMean(p1canvas));
+ p2canvas.writeTIFFfile("peterdejongEAAO_00_c2.tiff", mjr::ramCanvasPixelFilter::ScaleDownMean(p2canvas));
+ p3canvas.writeTIFFfile("peterdejongEAAO_00_c3.tiff", mjr::ramCanvasPixelFilter::ScaleDownMean(p3canvas));
+ p4canvas.writeTIFFfile("peterdejongEAAO_00_c4.tiff", mjr::ramCanvasPixelFilter::ScaleDownMean(p4canvas));
std::chrono::duration runTime = std::chrono::system_clock::now() - startTime;
std::cout << "Total Runtime " << runTime.count() << " sec" << std::endl;
diff --git a/examples/pickoverPopcorn.cpp b/examples/pickoverPopcorn.cpp
index 2d73fc9..320ec33 100644
--- a/examples/pickoverPopcorn.cpp
+++ b/examples/pickoverPopcorn.cpp
@@ -40,13 +40,13 @@
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
// This is *identical* to what we did in sic.cpp -- just way shorter.
-typedef mjr::ramCanvas1c16b::rcConverterColorScheme g2rgb8;
+typedef mjr::ramCanvasPixelFilter::ColorSchemeOnChan g2rgb8;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
int main(void) {
std::chrono::time_point startTime = std::chrono::system_clock::now();
- const int IMXSIZ = 7680/2;
- const int IMYSIZ = 4320/2;
+ const int IMXSIZ = 7680/8;
+ const int IMYSIZ = 4320/8;
const int NUMITR = 100;
const int spanx = 1;
const int spany = 1;
@@ -74,8 +74,11 @@ int main(void) {
}
}
hstRamCanvas.writeTIFFfile("pickoverPopcornCNT.tiff");
- g2rgb8 rcFilt(hstRamCanvas);
- hstRamCanvas.writeTIFFfile("pickoverPopcornCOL.tiff", rcFilt, false);
+ g2rgb8 pxFilt(hstRamCanvas);
+ hstRamCanvas.applyHomoPixTfrm(&mjr::ramCanvas1c16b::colorType::tfrmMultClamp, 10);
+ hstRamCanvas.applyHomoPixTfrm(&mjr::ramCanvas1c16b::colorType::tfrmMin, mjr::color3c8b::csCCfractal0RYBCW::numC-1);
+ hstRamCanvas.autoHistStrech();
+ hstRamCanvas.writeTIFFfile("pickoverPopcornCOL.tiff", pxFilt);
std::chrono::duration runTime = std::chrono::system_clock::now() - startTime;
std::cout << "Total Runtime " << runTime.count() << " sec" << std::endl;
return 0;
diff --git a/examples/sic.cpp b/examples/sic.cpp
index a3de79e..ee7aa24 100644
--- a/examples/sic.cpp
+++ b/examples/sic.cpp
@@ -76,10 +76,9 @@ std::vector> params {
};
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
-// This is *identical* to what we did in pickoverPopcorn.cpp -- just way shorter. It is longer still because we don't make
-// this a subclass of ramCanvasTpl::rcConverterHomoBase in order to illustrate how to implement a RC converter from scratch.
-// Also note we didn't need to DIY the color gradient with cmpRGBcornerDGradiant() as this gradient (0RYBCW) is available as
-// a pre-built color scheme: csCCfractal0RYBCW.
+// This is *identical* to what we did in pickoverPopcorn.cpp -- just way shorter. It is longer still because we don't make this a subclass of
+// mjr::ramCanvasPixelFilter::HomoBase in order to illustrate how to implement a RC pixel filter from scratch. Also note we didn't need to DIY the color
+// gradient with cmpRGBcornerDGradiant() as this gradient (0RYBCW) is available as a pre-built color scheme: csCCfractal0RYBCW.
class g2rgb8 {
private:
mjr::ramCanvas1c16b& attachedRC;
@@ -171,8 +170,8 @@ int main(void) {
cRamCanvas.writeTIFFfile("sicC_" + mjr::math::str::fmt_int(j, 2, '0') + ".tiff");
We have a better way. One that dosen't require the RAM to create a brand new canvas. We can use
the filter option of writeTIFFfile! */
- g2rgb8 rcFilt(theRamCanvas, maxII);
- theRamCanvas.writeTIFFfile("sicCC_" + mjr::math::str::fmt_int(j, 2, '0') + ".tiff", rcFilt, false);
+ g2rgb8 pxFilt(theRamCanvas, maxII);
+ theRamCanvas.writeTIFFfile("sicCC_" + mjr::math::str::fmt_int(j, 2, '0') + ".tiff", pxFilt, false);
}
std::chrono::duration runTime = std::chrono::system_clock::now() - startTime;
std::cout << "Total Runtime " << runTime.count() << " sec" << std::endl;
diff --git a/examples/simone_attractor.cpp b/examples/simone_attractor.cpp
index 04153c9..8043066 100644
--- a/examples/simone_attractor.cpp
+++ b/examples/simone_attractor.cpp
@@ -47,16 +47,13 @@
#include "MRMathSTR.hpp"
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
-// typedef mjr::ramCanvas3c8b rct;
-// typedef rct::colorType ct;
-
-typedef mjr::ramCanvas1c16b::rcConverterColorScheme g2rgb8;
+typedef mjr::ramCanvasPixelFilter::ColorSchemeOnChan g2rgb8;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
std::vector> params {
/* a b x0 y0 maxitr */
{ 3.69, 4.511, 0.0, 0.0, 100000000}, // 0
- { 3.64, 1.710, 0.0, 0.0, 100000000}, // 1
+ //{ 3.64, 1.710, 0.0, 0.0, 100000000}, // 1
};
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -89,9 +86,11 @@ int main(void) {
theRamCanvas.autoHistStrech();
theRamCanvas.applyHomoPixTfrm(&mjr::ramCanvas1c16b::colorType::tfrmLn1);
- g2rgb8 rcFilt(theRamCanvas);
+ //theRamCanvas.applyHomoPixTfrm(&mjr::ramCanvas1c16b::colorType::tfrmPow, 0.8);
+ theRamCanvas.autoHistStrech();
+ g2rgb8 pxFilt(theRamCanvas);
std::cout << "ITER(" << j << "): " << "TIFF" << std::endl;
- theRamCanvas.writeTIFFfile("simone_attractor_" + mjr::math::str::fmt_int(j, 2, '0') + ".tiff", rcFilt, true);
+ theRamCanvas.writeTIFFfile("simone_attractor_" + mjr::math::str::fmt_int(j, 2, '0') + ".tiff", pxFilt);
}
std::chrono::duration runTime = std::chrono::system_clock::now() - startTime;
std::cout << "Total Runtime " << runTime.count() << " sec" << std::endl;
diff --git a/lib/MRcolorTpl.hpp b/lib/MRcolorTpl.hpp
index 9fb0d84..7f1e62a 100644
--- a/lib/MRcolorTpl.hpp
+++ b/lib/MRcolorTpl.hpp
@@ -5207,7 +5207,7 @@ namespace mjr {
(redChanIdx != alphaChanIdx) &&
(greenChanIdx != blueChanIdx) &&
(greenChanIdx != alphaChanIdx) &&
- (blueChanIdx != alphaChanIdx)))) // Chans can't be teh same if non-negative
+ (blueChanIdx != alphaChanIdx)))) // Chans can't be the same if non-negative
inline std::ostream&
operator<< (std::ostream &out, colorTpl const& color) {
// MJR BUG NOTE operator<<: Will fail if 'char' is bigger than uint64_t -- I shudder to imagine a future that might bring such a condition..
@@ -5242,7 +5242,7 @@ namespace mjr {
(redChanIdx != alphaChanIdx) &&
(greenChanIdx != blueChanIdx) &&
(greenChanIdx != alphaChanIdx) &&
- (blueChanIdx != alphaChanIdx)))) // Chans can't be teh same if non-negative
+ (blueChanIdx != alphaChanIdx)))) // Chans can't be the same if non-negative
inline bool
operator!= (colorTpl const& color1, colorTpl const& color2) {
return color1.isNotEqual(color2);
diff --git a/lib/ramCanvasPixelFilters.hpp b/lib/ramCanvasPixelFilters.hpp
new file mode 100644
index 0000000..cb0a9f9
--- /dev/null
+++ b/lib/ramCanvasPixelFilters.hpp
@@ -0,0 +1,210 @@
+#ifndef MJR_INCLUDE_rcPixelFilters
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Put everything in the mjr namespace
+namespace mjr {
+ /** @brief Namespace for ramCanvas Pixel Filters.
+
+ mjr::ramCanvasPixelFilter objects attach to, and override, the minimal pixel access interface of another object. The idea is to provide an alternate
+ pixel access interface that may modify the data in transit. In this way they mjr::ramCanvasPixelFilter objects provide an alternate "view" of the pixel
+ data. For example mjr::ramCanvasTpl::writeTIFFfile() can use mjr::ramCanvasPixelFilter::RGBbyte to write a 24-bit RGB image from a source
+ mjr::ramCanvasTpl object containing floating point channels. Note that mjr::ramCanvasPixelFilter objects themselves provide a minimal pixel access
+ interface, and thus mjr::ramCanvasPixelFilter objects can be attached to other mjr::ramCanvasPixelFilter objects allowing one to chain together a list of
+ pixel data filters.
+
+ The minimal pixel access interface for a mjr::ramCanvasTpl-like object consists of the following seven members:
+
+ - isIntAxOrientationNaturalX()
+ - isIntAxOrientationNaturalY()
+ - getNumPixX()
+ - getNumPixY()
+ - getPxColorNC(x, y)
+ - colorType
+ - coordIntType
+
+ It is important to remember that mjr::ramCanvasPixelFilter objects can modify not just the pixel data but the size of a mjr::ramCanvasTpl object. For
+ example, mjr::ramCanvasPixelFilter::ScaleDownMean can be used to virtually resize a mjr::ramCanvasTpl object! For this reason it is important to use the
+ getNumPixX() and getNumPixY() methods when working with pixel data.
+
+ Note the pixel interface provided by mjr::ramCanvasPixelFilter objects might be described with the adjectives: *minimal*, *fast*, and *unsafe*! The
+ interface is unsafe in that it provides access to getPxColorNC() and *not* getPxColor(). That means no bounds checks are made on pixel coordinates. In
+ short, mjr::ramCanvasPixelFilter objects are intended to be consumed by code that has the necessary bounds checks built in. Keep this in mind if you use
+ them for something else!
+ */
+ namespace ramCanvasPixelFilter {
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /** @name ramCanvasTpl pixel filter classes. */
+ //@{
+ //--------------------------------------------------------------------------------------------------------------------------------------------------------
+ /** An incomplete class (no getPxColorNC method) that provides a nice base for homogeniouss pixel filters
+ \tparam sourceT The type of the ram canvas to filter. */
+ template
+ class FixGeomBase {
+ public:
+ sourceT& attachedRC;
+ FixGeomBase(sourceT& aRC) : attachedRC(aRC) { }
+ typedef typename sourceT::coordIntType coordIntType;
+ inline bool isIntAxOrientationNaturalX() { return attachedRC.isIntAxOrientationNaturalX(); }
+ inline bool isIntAxOrientationNaturalY() { return attachedRC.isIntAxOrientationNaturalY(); }
+ inline coordIntType getNumPixX() { return attachedRC.getNumPixX(); }
+ inline coordIntType getNumPixY() { return attachedRC.getNumPixY(); }
+ //virtual colorType getPxColorNC(coordIntType x, coordIntType y) = 0;
+ };
+ //--------------------------------------------------------------------------------------------------------------------------------------------------------
+ /** Identity filter -- i.e. NOP. */
+ template
+ class Identity : public FixGeomBase {
+ public:
+ Identity(sourceT& aRC) : FixGeomBase(aRC) { }
+ typedef typename sourceT::colorType colorType;
+ typedef typename sourceT::coordIntType coordIntType;
+ inline colorType getPxColorNC(coordIntType x, coordIntType y) { return FixGeomBase::attachedRC.getPxColorNC(x, y); }
+ };
+ //--------------------------------------------------------------------------------------------------------------------------------------------------------
+ /** Convert to an RGB color image with 8-bit integer channels. */
+ template
+ class RGBbyte : public FixGeomBase {
+ public:
+ RGBbyte(sourceT& aRC) : FixGeomBase(aRC) { }
+ typedef typename sourceT::colorType::colConRGBbyte colorType;
+ typedef typename sourceT::coordIntType coordIntType;
+ inline colorType getPxColorNC(coordIntType x, coordIntType y) { return FixGeomBase::attachedRC.getPxColorNC(x, y).getColConRGB_byte(); }
+ };
+ //--------------------------------------------------------------------------------------------------------------------------------------------------------
+ /** Convert to an RGBA color image with 8-bit integer channels. */
+ template
+ class RGBAbyte : public FixGeomBase {
+ public:
+ RGBAbyte(sourceT& aRC) : FixGeomBase(aRC) { }
+ typedef typename sourceT::colorType::colConRGBAbyte colorType;
+ typedef typename sourceT::coordIntType coordIntType;
+ inline colorType getPxColorNC(coordIntType x, coordIntType y) { return FixGeomBase::attachedRC.getPxColorNC(x, y).getColConRGBA_byte(); }
+ };
+ //--------------------------------------------------------------------------------------------------------------------------------------------------------
+ /** Convert to an RGB color image with 64-bit floating point channels. */
+ template
+ class RGBdbl : public FixGeomBase {
+ public:
+ RGBdbl(sourceT& aRC) : FixGeomBase(aRC) { }
+ typedef typename sourceT::colorType::colConRGBdbl colorType;
+ typedef typename sourceT::coordIntType coordIntType;
+ inline colorType getPxColorNC(coordIntType x, coordIntType y) { return FixGeomBase::attachedRC.getPxColorNC(x, y).getColConRGB_dbl(); }
+ };
+ //--------------------------------------------------------------------------------------------------------------------------------------------------------
+ /** Convert to an RGBA color image with 64-bit floating point channels. */
+ template
+ class RGBAdbl : public FixGeomBase {
+ public:
+ RGBAdbl(sourceT& aRC) : FixGeomBase(aRC) { }
+ typedef typename sourceT::colorType::colConRGBAdbl colorType;
+ typedef typename sourceT::coordIntType coordIntType;
+ inline colorType getPxColorNC(coordIntType x, coordIntType y) { return FixGeomBase::attachedRC.getPxColorNC(x, y).getColConRGBA_dbl(); }
+ };
+ //--------------------------------------------------------------------------------------------------------------------------------------------------------
+ /** Colorize by applying a color scheme to a single channel automatically mapping max channel value to max color scheme index.
+ \tparam outColorT Color type to return.
+ \tparam chan Channel to use from the input image. */
+ template
+ requires(std::same_as && (chan>=0) && (chan {
+ public:
+ ColorSchemeOnChan(sourceT& aRC) : FixGeomBase(aRC) { }
+ typedef outColorT colorType;
+ typedef typename sourceT::coordIntType coordIntType;
+ inline colorType getPxColorNC(coordIntType x, coordIntType y) {
+ if constexpr (sourceT::colorType::chanIsInt) {
+ return colorScheme::c(static_cast(mjr::math::linm::gen_map(static_cast(FixGeomBase::attachedRC.getPxColorNC(x, y).getChan(chan)),
+ static_cast(sourceT::colorType::minChanVal),
+ static_cast(sourceT::colorType::maxChanVal),
+ static_cast(0),
+ static_cast(colorScheme::numC - 1))));
+ } else {
+ return colorScheme::c(static_cast(FixGeomBase::attachedRC.getPxColorNC(x, y).getChan(chan)));
+ }
+ }
+ };
+ //--------------------------------------------------------------------------------------------------------------------------------------------------------
+ /** Monochrome transformation using colorT::intensityScaled(). */
+ template
+ class MonoIntensity : public FixGeomBase {
+ public:
+ MonoIntensity(sourceT& aRC) : FixGeomBase(aRC) { }
+ typedef colorTpl colorType;
+ typedef typename sourceT::coordIntType coordIntType;
+ inline colorType getPxColorNC(coordIntType x, coordIntType y) {
+ return static_cast(FixGeomBase::attachedRC.getPxColorNC(x, y).intensityScaled() * colorType::maxChanVal);
+ }
+ };
+ //--------------------------------------------------------------------------------------------------------------------------------------------------------
+ /** Scale down a canvis using a method similar to ramCanvasTpl::scaleDownMean(). */
+ template
+ class ScaleDownMean {
+ public:
+ sourceT& attachedRC;
+ ScaleDownMean(sourceT& aRC) : attachedRC(aRC) { }
+ typedef typename sourceT::colorType colorType;
+ typedef typename sourceT::coordIntType coordIntType;
+ inline bool isIntAxOrientationNaturalX() { return attachedRC.isIntAxOrientationNaturalX(); }
+ inline bool isIntAxOrientationNaturalY() { return attachedRC.isIntAxOrientationNaturalY(); }
+ inline coordIntType getNumPixX() { return attachedRC.getNumPixX() / factor; }
+ inline coordIntType getNumPixY() { return attachedRC.getNumPixY() / factor; }
+ inline colorType getPxColorNC(coordIntType x, coordIntType y) {
+ coordIntType x0 = x * factor;
+ coordIntType y0 = y * factor;
+ colorType retColor(static_cast(0));
+ for(int c=0; c(0);
+ for(coordIntType yi=0; yi(sum/factor/factor));
+ }
+ return retColor;
+ }
+ };
+ //--------------------------------------------------------------------------------------------------------------------------------------------------------
+ /** Rotate image 90 degrees clockwise. */
+ template
+ class Rotate90CW {
+ public:
+ sourceT& attachedRC;
+ Rotate90CW(sourceT& aRC) : attachedRC(aRC) { }
+ typedef typename sourceT::colorType colorType;
+ typedef typename sourceT::coordIntType coordIntType;
+ inline bool isIntAxOrientationNaturalX() { return attachedRC.isIntAxOrientationNaturalX(); }
+ inline bool isIntAxOrientationNaturalY() { return attachedRC.isIntAxOrientationNaturalY(); }
+ inline coordIntType getNumPixX() { return attachedRC.getNumPixY(); }
+ inline coordIntType getNumPixY() { return attachedRC.getNumPixX(); }
+ inline colorType getPxColorNC(coordIntType x, coordIntType y) { return attachedRC.getPxColorNC((attachedRC.getNumPixY()-1)-y, x); }
+ };
+
+
+ // //--------------------------------------------------------------------------------------------------------------------------------------------------------
+ // /** Combine three monochrome images into one RGB image. */
+ // template
+ // class CombineToRGB {
+ // public:
+ // sourceT& attachedRC1;
+ // sourceT& attachedRC2;
+ // sourceT& attachedRC3;
+ // CombineToRGB(sourceT& aRC1, sourceT& aRC2, sourceT& aRC3) : attachedRC1(aRC1), attachedRC2(aRC2), attachedRC3(aRC3) { }
+ // typedef typename sourceT::colorType colorType;
+ // typedef typename sourceT::coordIntType coordIntType;
+ // inline bool isIntAxOrientationNaturalX() { return attachedRC1.isIntAxOrientationNaturalX(); }
+ // inline bool isIntAxOrientationNaturalY() { return attachedRC1.isIntAxOrientationNaturalY(); }
+ // inline coordIntType getNumPixX() { return attachedRC1.getNumPixY(); }
+ // inline coordIntType getNumPixY() { return attachedRC1.getNumPixX(); }
+ // inline colorType getPxColorNC(coordIntType x, coordIntType y) { return attachedRC.getPxColorNC((attachedRC.getNumPixY()-1)-y, x); }
+ // };
+
+
+
+
+ //@}
+ }
+} // end namespace mjr
+
+#define MJR_INCLUDE_rcPixelFilters
+#endif
diff --git a/lib/ramCanvasTpl.hpp b/lib/ramCanvasTpl.hpp
index 6918574..784da86 100644
--- a/lib/ramCanvasTpl.hpp
+++ b/lib/ramCanvasTpl.hpp
@@ -37,6 +37,7 @@
#include "MRcolor.hpp"
#include "hersheyFont.hpp"
#include "MRpoint2d.hpp"
+#include "ramCanvasPixelFilters.hpp"
#include "MRMathIVL.hpp"
#include "MRMathFC.hpp"
@@ -145,88 +146,6 @@ namespace mjr {
class ramCanvasTpl {
public:
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /** @name Handy ramCanvasTpl converter classes. */
- //@{
- //--------------------------------------------------------------------------------------------------------------------------------------------------------
- /** This class is an incomplete rcConverter (no getPxColorNC method) that provides a nice base for homogenious rcConverters. */
- template
- class rcConverterHomoBase {
- public:
- inRamCanvasT& attachedRC;
- rcConverterHomoBase(inRamCanvasT& aRC) : attachedRC(aRC) { }
- inline bool isIntAxOrientationNaturalX() { return attachedRC.isIntAxOrientationNaturalX(); }
- inline bool isIntAxOrientationNaturalY() { return attachedRC.isIntAxOrientationNaturalY(); }
- inline typename inRamCanvasT::coordIntType getNumPixX() { return attachedRC.getNumPixX(); }
- inline typename inRamCanvasT::coordIntType getNumPixY() { return attachedRC.getNumPixY(); }
- };
- //--------------------------------------------------------------------------------------------------------------------------------------------------------
- template
- class rcConverterIdentity : public rcConverterHomoBase {
- public:
- rcConverterIdentity(inRamCanvasT& aRC) : rcConverterHomoBase(aRC) { }
- typedef typename inRamCanvasT::colorType colorType;
- inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase::attachedRC.getPxColorNC(x, y); }
- };
- //--------------------------------------------------------------------------------------------------------------------------------------------------------
- template
- class rcConverterRGBbyte : public rcConverterHomoBase {
- public:
- rcConverterRGBbyte(inRamCanvasT& aRC) : rcConverterHomoBase(aRC) { }
- typedef typename inRamCanvasT::colorType::colConRGBbyte colorType;
- inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase::attachedRC.getPxColorNC(x, y).getColConRGB_byte(); }
- };
- //--------------------------------------------------------------------------------------------------------------------------------------------------------
- template
- class rcConverterRGBAbyte {
- public:
- rcConverterRGBAbyte(inRamCanvasT& aRC) : rcConverterHomoBase(aRC) { }
- typedef typename inRamCanvasT::colorType::colConRGBAbyte colorType;
- inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase::attachedRC.getPxColorNC(x, y).getColConRGBA_byte(); }
- };
- //--------------------------------------------------------------------------------------------------------------------------------------------------------
- template
- class rcConverterRGBdbl {
- public:
- rcConverterRGBdbl(inRamCanvasT& aRC) : rcConverterHomoBase(aRC) { }
- typedef typename inRamCanvasT::colorType::colConRGBdbl colorType;
- inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase::attachedRC.getPxColorNC(x, y).getColConRGB_dbl(); }
- };
- //--------------------------------------------------------------------------------------------------------------------------------------------------------
- template
- class rcConverterRGBAdbl {
- public:
- rcConverterRGBAdbl(inRamCanvasT& aRC) : rcConverterHomoBase(aRC) { }
- typedef typename inRamCanvasT::colorType::colConRGBAdbl colorType;
- inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) { return rcConverterHomoBase::attachedRC.getPxColorNC(x, y).getColConRGBA_dbl(); }
- };
- //--------------------------------------------------------------------------------------------------------------------------------------------------------
- /** Colorize a ramCanvasTpl with integer channels using a color scheme. */
- template
- class rcConverterColorScheme : public rcConverterHomoBase {
- public:
- rcConverterColorScheme(inRamCanvasT& aRC) : rcConverterHomoBase(aRC) { }
- typedef outColorT colorType;
- inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) {
- typename outColorT::csIntType csi = static_cast(rcConverterHomoBase::attachedRC.getPxColorNC(x, y).getChan(chan) * factor);
- if (clamp)
- csi = mjr::math::ivl::clamp(csi, colorScheme::numC-1);
- return colorScheme::c(csi);
- }
- };
- //--------------------------------------------------------------------------------------------------------------------------------------------------------
- /** Convert a ramCanvasTpl to a greyscale image using colorT::intensity(). */
- template
- class rcConverterMonoIntensity : public rcConverterHomoBase {
- public:
- rcConverterMonoIntensity(inRamCanvasT& aRC) : rcConverterHomoBase(aRC) { }
- typedef colorTpl colorType;
- inline colorType getPxColorNC(typename inRamCanvasT::coordIntType x, typename inRamCanvasT::coordIntType y) {
- return static_cast(rcConverterHomoBase::attachedRC.getPxColorNC(x, y).intensity());
- }
- };
- //@}
-
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** @name Typedefs related to template parameters */
//@{
@@ -1397,7 +1316,7 @@ namespace mjr {
- Channels must be uint8_t, uint16_t, uint32_t, uint64_t, float (32-bit), or double (64-bit)
@param fileName The file name to write data to
- @param rcConverter An rcConverter object instance
+ @param pxFilter An pxFilter object instance
@param markAlpha If an alpha channel is present, then mark it as such in the TIFF file.
@return Status of I/O
@retval 0 Everything seems to have worked
@@ -1411,7 +1330,7 @@ namespace mjr {
@retval 9 Image has too few rows for TIFF format
@retval 10 Image rows are too large (too much data) for TIFF format
@retval 11 Image is too large (too much data) for TIFF format */
- template int writeTIFFfile(std::string fileName, rcConT rcConverter, bool markAlpha);
+ template int writeTIFFfile(std::string fileName, rcConT pxFilter, bool markAlpha = true);
//--------------------------------------------------------------------------------------------------------------------------------------------------------
/** Simplified overload for writeTIFFfile() that only requires the filename. */
int writeTIFFfile(std::string fileName, bool markAlpha = true);
@@ -1523,10 +1442,10 @@ namespace mjr {
0000000000000000256x0000000000000000128y000000000000000000000000003c00000000008bSGNsINTtLTLi
@param fileName The file name name to write data to
- @param rcConverter An rcConverter object instance
+ @param pxFilter An pxFilter object instance
@retval 0 The write was successful.
@retval 1 Could not open file. */
- template int writeRAWfile(std::string fileName, rcConT rcConverter);
+ template int writeRAWfile(std::string fileName, rcConT pxFilter);
//--------------------------------------------------------------------------------------------------------------------------------------------------------
/** Simplified overload for writeRAWfile() that only requires the filename. */
int writeRAWfile(std::string fileName);
@@ -2935,7 +2854,7 @@ namespace mjr {
requires (std::is_integral::value && std::is_signed::value && std::is_floating_point::value)
inline int
ramCanvasTpl::writeRAWfile(std::string fileName) {
- auto tmp = rcConverterIdentity>(*this);
+ auto tmp = mjr::ramCanvasPixelFilter::Identity>(*this);
return writeRAWfile(fileName, tmp);
}
@@ -2944,7 +2863,7 @@ namespace mjr {
requires (std::is_integral::value && std::is_signed::value && std::is_floating_point::value)
template
inline int
- ramCanvasTpl::writeRAWfile(std::string fileName, rcConT rcConverter) {
+ ramCanvasTpl::writeRAWfile(std::string fileName, rcConT pxFilter) {
std::ofstream outStream;
outStream.open(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
@@ -2954,8 +2873,8 @@ namespace mjr {
return 1;
outStream << "MJRRAW\n"; // 7 7
- outStream << std::setw(19) << std::setfill('0') << rcConverter.getNumPixX() << "x"; // 20 27
- outStream << std::setw(19) << std::setfill('0') << rcConverter.getNumPixY() << "y"; // 20 47
+ outStream << std::setw(19) << std::setfill('0') << pxFilter.getNumPixX() << "x"; // 20 27
+ outStream << std::setw(19) << std::setfill('0') << pxFilter.getNumPixY() << "y"; // 20 47
outStream << std::setw(27) << std::setfill('0') << rcConT::colorType::channelCount << "c"; // 28 75
outStream << std::setw(11) << std::setfill('0') << rcConT::colorType::bitsPerChan << "b"; // 12 87
outStream << (rcConT::colorType::chanIsUnsigned ? "UNS" : "SGN") << "s"; // 4 91
@@ -2965,12 +2884,12 @@ namespace mjr {
intCrdT x, y;
/* Normally I would not resort to such trickery; however, this is an exception. The following for loop is equivalent to switching between the two forms
- "for(y=(rcConverter.getNumPixY()-1); y>=0; y--)" and "for(y=0; y=0); (yNat?y++:y--)) {
- for((xNat?x=0:x=(rcConverter.getNumPixX()-1)); (xNat?x=0); (xNat?x++:x--)) {
- typename rcConT::colorType aColor = rcConverter.getPxColorNC(x, y);
+ "for(y=(pxFilter.getNumPixY()-1); y>=0; y--)" and "for(y=0; y=0); (yNat?y++:y--)) {
+ for((xNat?x=0:x=(pxFilter.getNumPixX()-1)); (xNat?x=0); (xNat?x++:x--)) {
+ typename rcConT::colorType aColor = pxFilter.getPxColorNC(x, y);
for(int c=0; c::value && std::is_signed::value && std::is_floating_point::value)
inline int
ramCanvasTpl::writeTIFFfile(std::string fileName, bool markAlpha) {
- rcConverterIdentity> tmp(*this);
+ mjr::ramCanvasPixelFilter::Identity> tmp(*this);
return writeTIFFfile(fileName, tmp, markAlpha);
}
@@ -2994,7 +2913,7 @@ namespace mjr {
requires (std::is_integral::value && std::is_signed::value && std::is_floating_point::value)
template
inline int
- ramCanvasTpl::writeTIFFfile(std::string fileName, rcConT rcConverter, bool markAlpha) {
+ ramCanvasTpl::writeTIFFfile(std::string fileName, rcConT pxFilter, bool markAlpha) {
if(rcConT::colorType::bitsPerChan < 8) // channels too thin
return 2;
@@ -3004,18 +2923,18 @@ namespace mjr {
return 4;
if(rcConT::colorType::channelCount > 0xffff) // too many channels
return 5;
- if(rcConverter.getNumPixX() < 1) // too skinny
+ if(pxFilter.getNumPixX() < 1) // too skinny
return 6;
- if(rcConverter.getNumPixX() > 0x7fffffff) // too wide
+ if(pxFilter.getNumPixX() > 0x7fffffff) // too wide
return 7;
- if(rcConverter.getNumPixY() < 1) // too short
+ if(pxFilter.getNumPixY() < 1) // too short
return 8;
- if(rcConverter.getNumPixY() > 0x7fffffff) // too tall
+ if(pxFilter.getNumPixY() > 0x7fffffff) // too tall
return 9;
- unsigned long bytesPerRow = rcConverter.getNumPixX() * rcConT::colorType::bitsPerChan / 8ul * rcConT::colorType::channelCount;
+ unsigned long bytesPerRow = pxFilter.getNumPixX() * rcConT::colorType::bitsPerChan / 8ul * rcConT::colorType::channelCount;
if(bytesPerRow > 0xffffffff) // rows too big
return 10;
- if(bytesPerRow * rcConverter.getNumPixY() > 0xfffffffff) // image too big
+ if(bytesPerRow * pxFilter.getNumPixY() > 0xfffffffff) // image too big
return 11;
// //grep -E '^#define[[:space:]]+(TIFF_BIGENDIAN|TIFF_LITTLEENDIAN|PHOTOMETRIC_RGB|PHOTOMETRIC_MINISBLACK|PLANARCONFIG_CONTIG|ORIENTATION_TOPLEFT|RESUNIT_NONE|SAMPLEFORMAT_UINT|SAMPLEFORMAT_IEEEFP)' /mingw64/include/tiff.h
@@ -3049,8 +2968,8 @@ namespace mjr {
endianType fe = platformEndianness(); // Endian Type
uint16_t endianNum = (fe == endianType::LITTLE ? tcTIFF_LITTLEENDIAN : tcTIFF_BIGENDIAN); // Endianness Magic Number
- uint32_t tifWidth = (uint32_t)rcConverter.getNumPixX(); // ImageWidth
- uint32_t tifLength = (uint32_t)rcConverter.getNumPixY(); // ImageLength & RowsPerStrip
+ uint32_t tifWidth = (uint32_t)pxFilter.getNumPixX(); // ImageWidth
+ uint32_t tifLength = (uint32_t)pxFilter.getNumPixY(); // ImageLength & RowsPerStrip
uint32_t tifSPP = (uint32_t)rcConT::colorType::channelCount; // SamplesPerPixel
uint16_t tifBPS = (uint16_t)(rcConT::colorType::bitsPerChan); // BitsPerSample
uint32_t bytePerSmp = tifBPS / 8; // Bytes per sample
@@ -3143,11 +3062,11 @@ namespace mjr {
writeUIntToStream(outStream, fe, 4, 0);
// Image data
intCrdT x, y;
- bool yNat = !(rcConverter.isIntAxOrientationNaturalY());
- bool xNat = rcConverter.isIntAxOrientationNaturalX();
- for((yNat?y=0:y=(rcConverter.getNumPixY()-1)); (yNat?y=0); (yNat?y++:y--)) {
- for((xNat?x=0:x=(rcConverter.getNumPixX()-1)); (xNat?x=0); (xNat?x++:x--)) {
- typename rcConT::colorType aColor = rcConverter.getPxColorNC(x, y);
+ bool yNat = !(pxFilter.isIntAxOrientationNaturalY());
+ bool xNat = pxFilter.isIntAxOrientationNaturalX();
+ for((yNat?y=0:y=(pxFilter.getNumPixY()-1)); (yNat?y=0); (yNat?y++:y--)) {
+ for((xNat?x=0:x=(pxFilter.getNumPixX()-1)); (xNat?x=0); (xNat?x++:x--)) {
+ typename rcConT::colorType aColor = pxFilter.getPxColorNC(x, y);
for(int c=0; c