/* This file is part of the Pangolin Project. * http://github.com/stevenlovegrove/Pangolin * * Copyright (c) 2013 Steven Lovegrove * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #include #include #include #include #include #include namespace pangolin { namespace internal { template std::pair GetMinMax(const Image& img, size_t channels) { const size_t max_channels = 3; const size_t colour_channels = std::min(channels, max_channels); std::pair chan_mm[max_channels]; for(size_t c = 0; c < max_channels; ++c) { chan_mm[c].first = +std::numeric_limits::max(); chan_mm[c].second = -std::numeric_limits::max(); } for(size_t y = 0; y < img.h; ++y) { T* pix = (T*)((char*)img.ptr + y * img.pitch); for(size_t x = 0; x < img.w; ++x) { for(size_t c = 0; c < colour_channels; ++c) { if(pix[c] < chan_mm[c].first) chan_mm[c].first = (float)pix[c]; if(pix[c] > chan_mm[c].second) chan_mm[c].second = (float)pix[c]; } pix += channels; } } // Find min / max of all channels, ignoring 4th alpha channel std::pair mm = chan_mm[0]; for(size_t c = 1; c < colour_channels; ++c) { mm.first = std::min(mm.first, chan_mm[c].first); mm.second = std::max(mm.second, chan_mm[c].second); } return mm; } template pangolin::Image GetImageRoi( pangolin::Image img, size_t channels, const pangolin::XYRangei& roi ) { return pangolin::Image( img.RowPtr(std::min(roi.y.min,roi.y.max)) + channels*std::min(roi.x.min,roi.x.max), roi.x.AbsSize(), roi.y.AbsSize(), img.pitch ); } template std::pair GetOffsetScale(const pangolin::Image& img, size_t channels, float type_max, float format_max) { // Find min / max of all channels, ignoring 4th alpha channel const std::pair mm = internal::GetMinMax(img,channels); const float type_scale = format_max / type_max; const float offset = -type_scale* mm.first; const float scale = type_max / (mm.second - mm.first); return std::pair(offset, scale); } template float GetScaleOnly(const pangolin::Image& img, size_t channels, float type_max, float /*format_max*/) { // Find min / max of all channels, ignoring 4th alpha channel const std::pair mm = internal::GetMinMax(img,channels); const float scale = type_max / mm.second; return scale; } } // internal inline std::pair GetMinMax( const Image& img, XYRangei iroi, const GlPixFormat& glfmt ) { using namespace internal; iroi.Clamp(0, (int)img.w - 1, 0, (int)img.h - 1); const size_t num_channels = pangolin::GlFormatChannels(glfmt.glformat); if(glfmt.gltype == GL_UNSIGNED_BYTE) { return GetMinMax(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels); } else if(glfmt.gltype == GL_UNSIGNED_SHORT) { return GetMinMax(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels); } else if(glfmt.gltype == GL_FLOAT) { return GetMinMax(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels); } else if(glfmt.gltype == GL_DOUBLE) { return GetMinMax(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels); } else { return std::pair(std::numeric_limits::max(), std::numeric_limits::lowest()); } } inline std::pair GetOffsetScale( const pangolin::Image& img, pangolin::XYRangei iroi, const pangolin::GlPixFormat& glfmt ) { using namespace internal; iroi.Clamp(0, (int)img.w-1, 0, (int)img.h-1 ); const size_t num_channels = pangolin::GlFormatChannels(glfmt.glformat); if(glfmt.gltype == GL_UNSIGNED_BYTE) { return GetOffsetScale(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 255.0f, 1.0f); }else if(glfmt.gltype == GL_UNSIGNED_SHORT) { return GetOffsetScale(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 65535.0f, 1.0f); }else if(glfmt.gltype == GL_FLOAT) { return GetOffsetScale(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 1.0f, 1.0f); }else if(glfmt.gltype == GL_DOUBLE) { return GetOffsetScale(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 1.0f, 1.0f); }else{ return std::pair(0.0f, 1.0f); } } inline float GetScaleOnly( const pangolin::Image& img, pangolin::XYRangei iroi, const pangolin::GlPixFormat& glfmt ) { using namespace internal; iroi.Clamp(0, (int)img.w-1, 0, (int)img.h-1 ); const size_t num_channels = pangolin::GlFormatChannels(glfmt.glformat); if(glfmt.gltype == GL_UNSIGNED_BYTE) { return GetScaleOnly(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 255.0f, 1.0f); }else if(glfmt.gltype == GL_UNSIGNED_SHORT) { return GetScaleOnly(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 65535.0f, 1.0f); }else if(glfmt.gltype == GL_FLOAT) { return GetScaleOnly(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 1.0f, 1.0f); }else if(glfmt.gltype == GL_DOUBLE) { return GetScaleOnly(GetImageRoi(img.template UnsafeReinterpret(), num_channels, iroi), num_channels, 1.0f, 1.0f); }else{ return 1.0f; } } }