QList initialization via initializer list - c++

My Hard drive got corrupted and I had to set everything up again.
The Problem is that previously working code is now throwing errors.
QList<QColor> colors = {
QColor(0, 255, 255, 255),
QColor(0, 200, 255, 255),
QColor(0, 170, 255, 255),
QColor(0, 150, 255, 255),
QColor(0, 130, 255, 255),
};
Error:
D:\dev\est_tsd\tests\testgis.cpp:19: error: C2440: ‘initializing’: cannot convert from 'initializer-list' to 'QList'
No constructor could take the source type, or constructor overload resolution was ambiguous
I read that Qt supports initializer list with QList now
(Name of the kit: Desktop Qt 5.3 MSVC2013 OpenGL 64bit). What am I missing?
Help would be much appreciated.

You are using copy initialization semantic instead of direct list initialization. You should check if you have in .pro file:
CONFIG += c++11
and then use:
QList<QColor> colors{
QColor(0, 255, 255, 255),
QColor(0, 200, 255, 255),
QColor(0, 170, 255, 255),
QColor(0, 150, 255, 255),
QColor(0, 130, 255, 255)
};

Try removing the last comma.
It becomes:
QList<QColor> colors = {
QColor(0, 255, 255, 255),
QColor(0, 200, 255, 255),
QColor(0, 170, 255, 255),
QColor(0, 150, 255, 255),
QColor(0, 130, 255, 255)};

Related

Does opencv have a constexpr vector or matrix container?

I would like to do something like this for example:
constexpr std::array<cv::Vec3b, 6> COLORS {
cv::Vec3b(0, 255, 0), // green
cv::Vec3b(255, 0, 0), // blue
cv::Vec3b(0, 0, 255), // red
cv::Vec3b(0, 255, 255), // yellow
cv::Vec3b(255, 0, 255), // magenta
cv::Vec3b(255, 255, 0) // cyan
}
However, cv::Vec3b cannot be made constexpr, is there support for constexpr containers in opencv? Or another way around this?
Compiler error:
error: the type ‘const std::vector<cv::Vec<unsigned char, 3> >’ of ‘constexpr’ variable ‘COLORS’ is not literal
};
Thank you

Translucent objects on IplImage

I draw objects on IplImage like this:
cvLine(image, point_1, point_2, color, thickness, CV_AA); // Line
cvCircle(mage, point, radius, color, thickness, CV_AA); // Circle
// and some others...
How can I draw them translucent? cv::Scalar does not support alpha channel, if I understand correctly. I found something similar, but not quite appropriate: link. Here we are talking about translucenty IplImage, not about the objects on it.
So, I tested it now with IplImage and cv::Mat, and both cvCircle and cv::circle don't support drawing semi-transparent objects. I used OpenCV 3.4.0, since this version still supports the old C API.
Let's have a look at the following code:
// IplImage - doesn't work
IplImage* ipl = cvCreateImage(cvSize(201, 201), IPL_DEPTH_8U, 4);
cvSet(ipl, CvScalar(255, 0, 0, 255));
cvCircle(ipl, CvPoint(100, 100), 50, CvScalar(0, 0, 255, 128), CV_FILLED);
// cv::Mat - doesn't work
cv::Mat img = cv::Mat(201, 201, CV_8UC4, cv::Scalar(255, 0, 0, 255));
cv::circle(img, cv::Point(100, 100), 50, cv::Scalar(0, 0, 255, 128), cv::FILLED);
We create a blue 4-channel image with zero transparency, and draw a red circle with 0.5 transparency. In both cases, we get the following output:
We see, that the part of red circle actually "replaces" the pixel values in the original blue image.
So, for IplImage as well as for cv::Mat we need to use blending, e.g. using addWeighted. Let's have a look at this code:
// IplImage - works
IplImage* iplBG = cvCreateImage(cvSize(201, 201), IPL_DEPTH_8U, 3);
cvSet(iplBG, CvScalar(255, 0, 0));
IplImage* iplFG = cvCreateImage(cvSize(201, 201), IPL_DEPTH_8U, 3);
cvSet(iplFG, CvScalar(0, 0, 0));
cvCircle(iplFG, CvPoint(100, 100), 50, CvScalar(0, 0, 255), CV_FILLED);
IplImage* iplOut = cvCreateImage(cvSize(201, 201), IPL_DEPTH_8U, 3);
cvAddWeighted(iplBG, 1, iplFG, 0.5, 0, iplOut);
// cv::Mat - works
cv::Mat imgBG = cv::Mat(201, 201, CV_8UC3, cv::Scalar(255, 0, 0));
cv::Mat imgFG = cv::Mat(201, 201, CV_8UC3, cv::Scalar(0, 0, 0));
cv::circle(imgFG, cv::Point(100, 100), 50, cv::Scalar(0, 0, 255), cv::FILLED);
cv::Mat imgOut;
cv::addWeighted(imgBG, 1, imgFG, 0.5, 0, imgOut);
In fact, we create a blue 3-channel background image like this:
And, we create a black foreground 3-channel image of the same size with the red circle:
Using addWeighted with alpha = 1 and beta = 0.5, we get the expected output for both versions:

Why printing images pixel values from a vector returns nonsense?

I have some code that looks at a directory of white and black images, reads it, resizes it and then pushes into a vector of images. However, when I call the images from the vector, it does not work. It prints out as if both images were white. What am I doing wrong here? Is it vector related?
vector<cv::Mat> images;
vector<cv::String> imageNames;
void prepareData(cv::String &directory)
{
cv::glob(directory, imageNames, false);
cv::Mat colorful, grey, out;
number = imageNames.size();
cout << "Number of images to train on " << number << endl;
for(size_t i = 0; i < number; i++)
{
colorful = cv::imread(imageNames[i]);
cv::resize(colorful, out, cv::Size(5, 5));
cv::cvtColor(out, grey, cv::COLOR_BGR2GRAY);
images.push_back(grey);
cout << grey << endl;
}
for (int i = 0; i < number; ++i)
{
cout << "IMAGE " << i << " " << images[i] << endl;
}
Here is the output I get. The 2 images at first show proper pixel values of the image (23 -> black, 255 -> white), but the second I recall it from the vector, I get that both of my images are white. What am I doing wrong?
Number of images to train on 2
[23, 23, 23, 23, 23;
23, 23, 23, 23, 23;
23, 23, 23, 23, 23;
23, 23, 23, 23, 23;
23, 23, 23, 23, 23]
[255, 255, 255, 255, 255;
255, 255, 255, 255, 255;
254, 254, 255, 255, 255;
254, 255, 255, 255, 254;
255, 255, 255, 255, 255]
IMAGE 0 [255, 255, 255, 255, 255;
255, 255, 255, 255, 255;
254, 254, 255, 255, 255;
254, 255, 255, 255, 254;
255, 255, 255, 255, 255]
IMAGE 1 [255, 255, 255, 255, 255;
255, 255, 255, 255, 255;
254, 254, 255, 255, 255;
254, 255, 255, 255, 254;
255, 255, 255, 255, 255]
Copy operation of cv::Mat doesn't copy underlying data. cv::Mat uses reference counter mechanism. When copy is done, ref counter of copied matrix is increased, no data is copied.
Consider the code below:
vector<cv::Mat> vec;
cv::Mat m1;
vec.push_back(m1); // vec[0] refers to m1
some operations on m1
now the printed content of vec[0] and m1 will be the same.
In for loop you are pushing two new instances of cv::Mat but they refer to grey data. So when you are printing contents of vector, you see the last modification on grey matrix.
Create out and grey as local inside for loop:
colorful = cv::imread(imageNames[i]);
cv::Mat out, grey; // <----- added
cv::resize(colorful, out, cv::Size(5, 5));
cv::cvtColor(out, grey, cv::COLOR_BGR2GRAY);
images.push_back(grey);
cout << grey << endl;
Another solution is to use clone method that makes deep copy of cv::Mat.

OpenCv overlay multiple Mat partly using masks

Hi following up on this brillant way of copying polygons to an other Mat in OpenCv overlay two Mat (drawings not images) with transparency I need to advanced this a bit.
Besides just copying Mats with polygons, I need to copy these polygons ONTO a image. Below you can find my MWE of this.
Following the above mentioned answer I load an additional image called bg in this case (as well 100x100px). What I believed is using inRange again on the result gives me the mask of all polygons (which is working). And than using copyTo to copy all that is in the mask. It copies the pixels from the "background image", but colouring the polygons in black insted of its regular colours.
Any ideas what I forgot to consider in this case?
PS: drawing the polygons directly onto the image is not possible. The code below is just a MWE and in the code below I left out an loop for readability reasons.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main(int argc, char **argv)
{
cv::Mat bg = imread("bg.png");
cv::Mat m1(100, 100, CV_8UC4, cv::Scalar(0, 0, 0, 0));
cv::Mat m2(m1);
cv::Mat m3(m1);
cv::Mat m4(m1);
cv::polylines(m1, std::vector<cv::Point>{cv::Point{ 100, 20 }, cv::Point{ 0, 40 }}, true, cv::Scalar(6, 6, 255, 255));
cv::polylines(m2, std::vector<cv::Point>{cv::Point{ 100, 100 }, cv::Point{ 0, 0 }}, true, cv::Scalar(192, 112, 0, 255));
cv::polylines(m3, std::vector<cv::Point>{cv::Point{ 0, 50 }, cv::Point{ 100, 50 }}, true, cv::Scalar(0, 228, 0, 255));
cv::polylines(m4, std::vector<cv::Point>{cv::Point{ 20, 0 }, cv::Point{ 20, 100 }}, true, cv::Scalar(0, 228, 255, 0 ));
cv::Mat mask;
cv::Mat result(m1.clone());
cv::inRange(m2, cv::Scalar(0, 0, 0, 0), cv::Scalar(0, 0, 0, 0), mask);
mask = 255 - mask; // invert the mask
m2.copyTo(result, mask);
cv::inRange(result, cv::Scalar(0, 0, 0, 0), cv::Scalar(0, 0, 0, 0), mask);
m3.copyTo(result, mask);
cv::inRange(result, cv::Scalar(0, 0, 0, 0), cv::Scalar(0, 0, 0, 0), mask);
m4.copyTo(result, mask);
cv::inRange(result, cv::Scalar(0, 0, 0, 0), cv::Scalar(0, 0, 0, 0), mask);
bg.copyTo(result, mask);
namedWindow("result", cv::WINDOW_AUTOSIZE);
imshow("result", result);
}

How create text with Linear Gradient?

Create LinearGradientBrush
LinearGradientBrush linGrBrush(
Point(0, 10),
Point(200, 10),
Color(255, 255, 0, 0),
Color(255, 0, 0, 255)
);
How I can draw text using this gradient?
LinearGradientBrush *linGrBrush=new LinearGradientBrush(
Point(0, 10),
Point(200, 10),
Color(255, 255, 0, 0),
Color(255, 0, 0, 255));
Graphics *graphics=new Graphics(hdc);
PointF drawPoint = PointF(150.0F,150.0F);
SolidBrush* myBrush = new SolidBrush(Color::Black);
graphics->DrawString(L"Test text",strlen("Test text"),fn,drawPoint,linGrBrush);