Skip to content
Snippets Groups Projects
Commit 8a1c61a2 authored by Daniel Müller's avatar Daniel Müller
Browse files

* Fixed image layer pixels and tag color comparisons

parent 3c4918dd
No related branches found
No related tags found
No related merge requests found
/****************************************************************************** /******************************************************************************
* File: CVUtils.cpp * File: CVUtils.cpp
* Date: 19.2.2018 * Date: 19.2.2018
*****************************************************************************/ *****************************************************************************/
#include "Grinder.h" #include "Grinder.h"
#include "CVUtils.h" #include "CVUtils.h"
#include "image/ImageExceptions.h" #include "image/ImageExceptions.h"
QImage CVUtils::matrixToImage(const cv::Mat& matrix) QImage CVUtils::matrixToImage(const cv::Mat& matrix)
{ {
cv::Mat imageMatrix = matrix; cv::Mat imageMatrix = matrix;
// Check if the matrix has an unsupported type; if so, convert it first // Check if the matrix has an unsupported type; if so, convert it first
if (matrix.type() != CV_8UC4 && matrix.type() != CV_8UC3 && matrix.type() != CV_8UC1) if (matrix.type() != CV_8UC4 && matrix.type() != CV_8UC3 && matrix.type() != CV_8UC1)
{ {
matrix.convertTo(imageMatrix, CV_8U); matrix.convertTo(imageMatrix, CV_8U);
cv::normalize(imageMatrix, imageMatrix, std::numeric_limits<unsigned char>::max(), std::numeric_limits<unsigned char>::min(), cv::NORM_MINMAX); cv::normalize(imageMatrix, imageMatrix, std::numeric_limits<unsigned char>::max(), std::numeric_limits<unsigned char>::min(), cv::NORM_MINMAX);
} }
switch (imageMatrix.type()) switch (imageMatrix.type())
{ {
case CV_8UC4: case CV_8UC4:
return QImage(imageMatrix.data, imageMatrix.cols, imageMatrix.rows, static_cast<int>(imageMatrix.step), QImage::Format_ARGB32); return QImage(imageMatrix.data, imageMatrix.cols, imageMatrix.rows, static_cast<int>(imageMatrix.step), QImage::Format_ARGB32);
case CV_8UC3: case CV_8UC3:
return QImage(imageMatrix.data, imageMatrix.cols, imageMatrix.rows, static_cast<int>(imageMatrix.step), QImage::Format_RGB888).rgbSwapped(); return QImage(imageMatrix.data, imageMatrix.cols, imageMatrix.rows, static_cast<int>(imageMatrix.step), QImage::Format_RGB888).rgbSwapped();
case CV_8UC1: case CV_8UC1:
return QImage(imageMatrix.data, imageMatrix.cols, imageMatrix.rows, static_cast<int>(imageMatrix.step), QImage::Format_Grayscale8); return QImage(imageMatrix.data, imageMatrix.cols, imageMatrix.rows, static_cast<int>(imageMatrix.step), QImage::Format_Grayscale8);
default: default:
throw ImageException{_EXCPT("Unsupported matrix format for conversion to an image")}; throw ImageException{_EXCPT("Unsupported matrix format for conversion to an image")};
} }
} }
QPixmap CVUtils::matrixToPixmap(const cv::Mat& matrix) QPixmap CVUtils::matrixToPixmap(const cv::Mat& matrix)
{ {
return QPixmap::fromImage(matrixToImage(matrix)); return QPixmap::fromImage(matrixToImage(matrix));
} }
QColor CVUtils::colorToGrayscale(QColor color) QColor CVUtils::colorToGrayscale(QColor color)
{ {
auto p = static_cast<int>(std::lround((color.red() + color.green() + color.blue()) / 3.0f)); auto p = static_cast<int>(std::lround((color.red() + color.green() + color.blue()) / 3.0f));
return QColor{p, p, p}; return QColor{p, p, p};
} }
bool CVUtils::compareColors(QColor clr1, QColor clr2, float tolerance, bool perceivedDifference) bool CVUtils::compareColors(QColor clr1, QColor clr2, float tolerance, bool perceivedDifference)
{ {
if (tolerance >= 1.0f) if (tolerance >= 1.0f)
{ {
return true; return true;
} }
else if (!clr1.isValid() || !clr2.isValid()) else if (!clr1.isValid() || !clr2.isValid())
{ {
return false; return false;
} }
else if (tolerance > 0.0f) else if (tolerance > 0.0f)
{ {
if (perceivedDifference) if (perceivedDifference)
{ {
// Based on https://www.compuphase.com/cmetric.htm // Based on https://www.compuphase.com/cmetric.htm
auto rmean = (clr1.red() + clr2.red() ) / 2; auto rmean = (clr1.red() + clr2.red() ) / 2;
auto r = clr1.red() - clr2.red(); auto r = clr1.red() - clr2.red();
auto g = clr1.green() - clr2.green(); auto g = clr1.green() - clr2.green();
auto b = clr1.blue()- clr2.blue(); auto b = clr1.blue()- clr2.blue();
auto delta = std::sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8)); auto delta = std::sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8));
auto rate = static_cast<float>(delta / 650.0f); auto rate = static_cast<float>(delta / 650.0f);
return rate <= tolerance; return rate <= tolerance;
} }
else else
{ {
// Euklidean distance // Euklidean distance
float sum = 0; float sum = 0;
auto diff = clr1.red() - clr2.red(); auto diff = clr1.red() - clr2.red();
sum += diff * diff; sum += diff * diff;
diff = clr1.green() - clr2.green(); diff = clr1.green() - clr2.green();
sum += diff * diff; sum += diff * diff;
diff = clr1.blue() - clr2.blue(); diff = clr1.blue() - clr2.blue();
sum += diff * diff; sum += diff * diff;
return static_cast<float>((sum / 3.0f) / 255.0f) <= tolerance; return static_cast<float>((sum / 3.0f) / 255.0f) <= tolerance;
} }
} }
else else
return clr1 == clr2; return clr1 == clr2;
} }
std::vector<QColor> CVUtils::generateColors(unsigned int count, float saturation, float value) bool CVUtils::compareColorsNoAlpha(QColor clr1, QColor clr2)
{ {
std::vector<QColor> colors; return clr1.red() == clr2.red() && clr1.green() == clr2.green() && clr1.blue() == clr2.blue();
float colorStep = 1.0f / count; }
for (unsigned int i = 0; i < count; ++i) std::vector<QColor> CVUtils::generateColors(unsigned int count, float saturation, float value)
{ {
QColor color; std::vector<QColor> colors;
color.setHsvF(i * colorStep, saturation, value); float colorStep = 1.0f / count;
colors.push_back(color);
} for (unsigned int i = 0; i < count; ++i)
{
return colors; QColor color;
} color.setHsvF(i * colorStep, saturation, value);
colors.push_back(color.toRgb());
QColor CVUtils::mixColors(QColor clr1, QColor clr2, float alpha) }
{
auto red = (1 - alpha) * clr1.redF() + alpha * clr2.redF(); return colors;
auto green = (1 - alpha) * clr1.greenF() + alpha * clr2.greenF(); }
auto blue = (1 - alpha) * clr1.blueF() + alpha * clr2.blueF();
QColor CVUtils::mixColors(QColor clr1, QColor clr2, float alpha)
QColor color; {
color.setRgbF(red, green, blue); auto red = (1 - alpha) * clr1.redF() + alpha * clr2.redF();
return color; auto green = (1 - alpha) * clr1.greenF() + alpha * clr2.greenF();
} auto blue = (1 - alpha) * clr1.blueF() + alpha * clr2.blueF();
QColor color;
color.setRgbF(red, green, blue);
return color;
}
/****************************************************************************** /******************************************************************************
* File: CVUtils.h * File: CVUtils.h
* Date: 19.2.2018 * Date: 19.2.2018
*****************************************************************************/ *****************************************************************************/
#ifndef CVUTILS_H #ifndef CVUTILS_H
#define CVUTILS_H #define CVUTILS_H
#include <QString> #include <QString>
#include <QImage> #include <QImage>
#include <functional> #include <functional>
#include <opencv2/core.hpp> #include <opencv2/core.hpp>
namespace grndr namespace grndr
{ {
class CVUtils final class CVUtils final
{ {
public: public:
static QImage matrixToImage(const cv::Mat& matrix); static QImage matrixToImage(const cv::Mat& matrix);
static QPixmap matrixToPixmap(const cv::Mat& matrix); static QPixmap matrixToPixmap(const cv::Mat& matrix);
template<typename DataType> template<typename DataType>
static QString matrixToString(const cv::Mat& matrix); static QString matrixToString(const cv::Mat& matrix);
template<typename DataType> template<typename DataType>
static QString matrixToString(const cv::Mat& matrix, std::function<QString(const DataType&)> formatter); static QString matrixToString(const cv::Mat& matrix, std::function<QString(const DataType&)> formatter);
static QColor colorToGrayscale(QColor color); static QColor colorToGrayscale(QColor color);
static bool compareColors(QColor clr1, QColor clr2, float tolerance = 0.0f, bool perceivedDifference = true); static bool compareColors(QColor clr1, QColor clr2, float tolerance = 0.0f, bool perceivedDifference = true);
static std::vector<QColor> generateColors(unsigned int count, float saturation = 1.0, float value = 1.0); static bool compareColorsNoAlpha(QColor clr1, QColor clr2);
static QColor mixColors(QColor clr1, QColor clr2, float alpha); static std::vector<QColor> generateColors(unsigned int count, float saturation = 1.0, float value = 1.0);
static QColor mixColors(QColor clr1, QColor clr2, float alpha);
private:
CVUtils() { } private:
}; CVUtils() { }
} };
}
#include "CVUtils.impl.h"
#include "CVUtils.impl.h"
#endif
#endif
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "ImageTags.h" #include "ImageTags.h"
#include "ImageExceptions.h" #include "ImageExceptions.h"
#include "LayerPixels.h" #include "LayerPixels.h"
#include "cv/CVUtils.h"
ImageTagsBitmap::ImageTagsBitmap(const ImageTags* imageTags, QSize bitmapSize) : ImageTagsBitmap::ImageTagsBitmap(const ImageTags* imageTags, QSize bitmapSize) :
_imageTags{imageTags}, _imageTagsBitmap{bitmapSize} _imageTags{imageTags}, _imageTagsBitmap{bitmapSize}
...@@ -39,7 +40,7 @@ void ImageTagsBitmap::renderLayerPixels(const LayerPixels& layerPixels, const Im ...@@ -39,7 +40,7 @@ void ImageTagsBitmap::renderLayerPixels(const LayerPixels& layerPixels, const Im
{ {
QRgb rgb = pixelsData[c]; QRgb rgb = pixelsData[c];
if (rgb != 0 && (assignToAll || QColor{qRed(rgb), qGreen(rgb), qBlue(rgb)} == imageTag->getColor())) if (rgb != 0 && (assignToAll || CVUtils::compareColorsNoAlpha(QColor{qRed(rgb), qGreen(rgb), qBlue(rgb)}, imageTag->getColor())))
canvasData[c] = rgb; canvasData[c] = rgb;
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment