// Copyright (c) 2022, ETH Zurich and UNC Chapel Hill. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of // its contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de) #ifndef COLMAP_SRC_UTIL_BITMAP_H_ #define COLMAP_SRC_UTIL_BITMAP_H_ #include #include #include #include #include #include #include #ifdef _WIN32 #define NOMINMAX #include #endif #include #include "util/string.h" namespace colmap { // Templated bitmap color class. template struct BitmapColor { BitmapColor(); BitmapColor(const T gray); BitmapColor(const T r, const T g, const T b); template BitmapColor Cast() const; bool operator==(const BitmapColor& rhs) const; bool operator!=(const BitmapColor& rhs) const; template friend std::ostream& operator<<(std::ostream& output, const BitmapColor& color); T r; T g; T b; }; // Wrapper class around FreeImage bitmaps. class Bitmap { public: Bitmap(); // Copy constructor. Bitmap(const Bitmap& other); // Move constructor. Bitmap(Bitmap&& other); // Create bitmap object from existing FreeImage bitmap object. Note that // this class takes ownership of the object. explicit Bitmap(FIBITMAP* data); // Copy assignment. Bitmap& operator=(const Bitmap& other); // Move assignment. Bitmap& operator=(Bitmap&& other); // Allocate bitmap by overwriting the existing data. bool Allocate(const int width, const int height, const bool as_rgb); // Deallocate the bitmap by releasing the existing data. void Deallocate(); // Get pointer to underlying FreeImage object. inline const FIBITMAP* Data() const; inline FIBITMAP* Data(); // Dimensions of bitmap. inline int Width() const; inline int Height() const; inline int Channels() const; // Number of bits per pixel. This is 8 for grey and 24 for RGB image. inline unsigned int BitsPerPixel() const; // Scan width of bitmap which differs from the actual image width to achieve // 32 bit aligned memory. Also known as pitch or stride. inline unsigned int ScanWidth() const; // Check whether image is grey- or colorscale. inline bool IsRGB() const; inline bool IsGrey() const; // Number of bytes required to store image. size_t NumBytes() const; // Copy raw image data to array. std::vector ConvertToRawBits() const; std::vector ConvertToRowMajorArray() const; std::vector ConvertToColMajorArray() const; // Manipulate individual pixels. For grayscale images, only the red element // of the RGB color is used. bool GetPixel(const int x, const int y, BitmapColor* color) const; bool SetPixel(const int x, const int y, const BitmapColor& color); // Get pointer to y-th scanline, where the 0-th scanline is at the top. const uint8_t* GetScanline(const int y) const; // Fill entire bitmap with uniform color. For grayscale images, the first // element of the vector is used. void Fill(const BitmapColor& color); // Interpolate color at given floating point position. bool InterpolateNearestNeighbor(const double x, const double y, BitmapColor* color) const; bool InterpolateBilinear(const double x, const double y, BitmapColor* color) const; // Extract EXIF information from bitmap. Returns false if no EXIF information // is embedded in the bitmap. bool ExifCameraModel(std::string* camera_model) const; bool ExifFocalLength(double* focal_length) const; bool ExifLatitude(double* latitude) const; bool ExifLongitude(double* longitude) const; bool ExifAltitude(double* altitude) const; // Read bitmap at given path and convert to grey- or colorscale. bool Read(const std::string& path, const bool as_rgb = true); // Write image to file. Flags can be used to set e.g. the JPEG quality. // Consult the FreeImage documentation for all available flags. bool Write(const std::string& path, const FREE_IMAGE_FORMAT format = FIF_UNKNOWN, const int flags = 0) const; // Smooth the image using a Gaussian kernel. void Smooth(const float sigma_x, const float sigma_y); // Rescale image to the new dimensions. void Rescale(const int new_width, const int new_height, const FREE_IMAGE_FILTER filter = FILTER_BILINEAR); // Clone the image to a new bitmap object. Bitmap Clone() const; Bitmap CloneAsGrey() const; Bitmap CloneAsRGB() const; // Clone metadata from this bitmap object to another target bitmap object. void CloneMetadata(Bitmap* target) const; // Read specific EXIF tag. bool ReadExifTag(const FREE_IMAGE_MDMODEL model, const std::string& tag_name, std::string* result) const; private: typedef std::unique_ptr FIBitmapPtr; void SetPtr(FIBITMAP* data); static bool IsPtrGrey(FIBITMAP* data); static bool IsPtrRGB(FIBITMAP* data); static bool IsPtrSupported(FIBITMAP* data); FIBitmapPtr data_; int width_; int height_; int channels_; }; // Jet colormap inspired by Matlab. Grayvalues are expected in the range [0, 1] // and are converted to RGB values in the same range. class JetColormap { public: static float Red(const float gray); static float Green(const float gray); static float Blue(const float gray); private: static float Interpolate(const float val, const float y0, const float x0, const float y1, const float x1); static float Base(const float val); }; //////////////////////////////////////////////////////////////////////////////// // Implementation //////////////////////////////////////////////////////////////////////////////// namespace internal { template T2 BitmapColorCast(const T1 value) { return std::min(static_cast(std::numeric_limits::max()), std::max(static_cast(std::numeric_limits::min()), std::round(value))); } } // namespace internal template BitmapColor::BitmapColor() : r(0), g(0), b(0) {} template BitmapColor::BitmapColor(const T gray) : r(gray), g(gray), b(gray) {} template BitmapColor::BitmapColor(const T r, const T g, const T b) : r(r), g(g), b(b) {} template template BitmapColor BitmapColor::Cast() const { BitmapColor color; color.r = internal::BitmapColorCast(r); color.g = internal::BitmapColorCast(g); color.b = internal::BitmapColorCast(b); return color; } template bool BitmapColor::operator==(const BitmapColor& rhs) const { return r == rhs.r && g == rhs.g && b == rhs.b; } template bool BitmapColor::operator!=(const BitmapColor& rhs) const { return r != rhs.r || g != rhs.g || b != rhs.b; } template std::ostream& operator<<(std::ostream& output, const BitmapColor& color) { output << StringPrintf("RGB(%f, %f, %f)", static_cast(color.r), static_cast(color.g), static_cast(color.b)); return output; } FIBITMAP* Bitmap::Data() { return data_.get(); } const FIBITMAP* Bitmap::Data() const { return data_.get(); } int Bitmap::Width() const { return width_; } int Bitmap::Height() const { return height_; } int Bitmap::Channels() const { return channels_; } unsigned int Bitmap::BitsPerPixel() const { return FreeImage_GetBPP(data_.get()); } unsigned int Bitmap::ScanWidth() const { return FreeImage_GetPitch(data_.get()); } bool Bitmap::IsRGB() const { return channels_ == 3; } bool Bitmap::IsGrey() const { return channels_ == 1; } } // namespace colmap #endif // COLMAP_SRC_UTIL_BITMAP_H_