Rotate image and with loss of quality - c++

I have this code that rotates an image. But the result is an image with a transparency effect (https://pixs.ru/image/G82BPR - like this) that accumulates with each call to this function. I want to get the image on the output in its original form, but inverted and have no idea what to do. Thanks if you have any advice.
bool rotate_sticker(GdkEventScroll* scroll, const unsigned int inx) {
Gtk::Image* img = dynamic_cast<Gtk::Image*>(small_stickers[inx]->get_child());
Glib::RefPtr< Gdk::Pixbuf > old_pixbuf = img->get_pixbuf();
Glib::RefPtr<Gdk::Window> win = small_stickers[inx]->get_window();
Cairo::RefPtr<Cairo::Region> region = Cairo::Region::create();
Glib::RefPtr<Gdk::DrawingContext> draw_context = win->begin_draw_frame(region);
const double degree = 5;
const double w = 135;
const double h = 135;
Cairo::RefPtr<Cairo::ImageSurface> surface = Cairo::ImageSurface::create(Cairo::Format::FORMAT_ARGB32,w,h);
Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface);
//rotate by central point
cr->translate (w*0.5, h*0.5);
cr->rotate_degrees(degree);
cr->translate (-0.5*w, -0.5*h);
Gdk::Cairo::set_source_pixbuf(cr,old_pixbuf);
cr->paint();
win->end_draw_frame(draw_context);
img->set(Gdk::Pixbuf::create(cr->get_target(),0,0,w,h));
return true;
}

Related

My C++ code is not detecting objects correctly yolov5

I have a yolov5 onnx file where I trained apples and bananas. I was using python until today, but I decided to switch to c++ to gain some speed. I get correct results when I use yolov5's own onnx files and image in the code I added below. But when I add my own onnx file and my test image it gives me wrong result. You can also find the attached image. What is the problem here?
// Include Libraries.
\#include \<opencv2/opencv.hpp\>
\#include \<fstream\>
// Namespaces.
using namespace cv;
using namespace std;
using namespace cv::dnn;
// Constants.
const float INPUT_WIDTH = 640.0;
const float INPUT_HEIGHT = 640.0;
const float SCORE_THRESHOLD = 0.3;
const float NMS_THRESHOLD = 0.4;
const float CONFIDENCE_THRESHOLD = 0.65;
// Text parameters.
const float FONT_SCALE = 0.7;
const int FONT_FACE = FONT_HERSHEY_SIMPLEX;
const int THICKNESS = 1;
// Colors.
Scalar BLACK = Scalar(0,0,0);
Scalar BLUE = Scalar(255, 178, 50);
Scalar YELLOW = Scalar(0, 255, 255);
Scalar RED = Scalar(0,0,255);
// Draw the predicted bounding box.
void draw_label(Mat& input_image, string label, int left, int top)
{
// Display the label at the top of the bounding box.
int baseLine;
Size label_size = getTextSize(label, FONT_FACE, FONT_SCALE, THICKNESS, &baseLine);
top = max(top, label_size.height);
// Top left corner.
Point tlc = Point(left, top);
// Bottom right corner.
Point brc = Point(left + label_size.width, top + label_size.height + baseLine);
// Draw black rectangle.
rectangle(input_image, tlc, brc, BLACK, FILLED);
// Put the label on the black rectangle.
putText(input_image, label, Point(left, top + label_size.height), FONT_FACE, FONT_SCALE, YELLOW, THICKNESS);
}
vector\<Mat\> pre_process(Mat &input_image, Net &net)
{
// Convert to blob.
Mat blob;
blobFromImage(input_image, blob, 1./255., Size(INPUT_WIDTH, INPUT_HEIGHT), Scalar(), true, false);
net.setInput(blob);
// Forward propagate.
vector<Mat> outputs;
net.forward(outputs, net.getUnconnectedOutLayersNames());
return outputs;
}
Mat post_process(Mat &input_image, vector\<Mat\> &outputs, const vector\<string\> &class_name)
{
// Initialize vectors to hold respective outputs while unwrapping detections.
vector\<int\> class_ids;
vector\<float\> confidences;
vector\<Rect\> boxes;
// Resizing factor.
float x_factor = input_image.cols / INPUT_WIDTH;
float y_factor = input_image.rows / INPUT_HEIGHT;
float *data = (float *)outputs[0].data;
const int dimensions = 85;
const int rows = 25200;
// Iterate through 25200 detections.
for (int i = 0; i < rows; ++i)
{
float confidence = data[4];
// Discard bad detections and continue.
if (confidence >= CONFIDENCE_THRESHOLD)
{
float * classes_scores = data + 5;
// Create a 1x85 Mat and store class scores of 80 classes.
Mat scores(1, class_name.size(), CV_32FC1, classes_scores);
// Perform minMaxLoc and acquire index of best class score.
Point class_id;
double max_class_score;
minMaxLoc(scores, 0, &max_class_score, 0, &class_id);
// Continue if the class score is above the threshold.
if (max_class_score > SCORE_THRESHOLD)
{
// Store class ID and confidence in the pre-defined respective vectors.
confidences.push_back(confidence);
class_ids.push_back(class_id.x);
// Center.
float cx = data[0];
float cy = data[1];
// Box dimension.
float w = data[2];
float h = data[3];
// Bounding box coordinates.
int left = int((cx - 0.5 * w) * x_factor);
int top = int((cy - 0.5 * h) * y_factor);
int width = int(w * x_factor);
int height = int(h * y_factor);
// Store good detections in the boxes vector.
boxes.push_back(Rect(left, top, width, height));
}
}
// Jump to the next column.
data += 85;
}
// Perform Non Maximum Suppression and draw predictions.
vector<int> indices;
NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, indices);
for (int i = 0; i < indices.size(); i++)
{
int idx = indices[i];
Rect box = boxes[idx];
int left = box.x;
int top = box.y;
int width = box.width;
int height = box.height;
// Draw bounding box.
rectangle(input_image, Point(left, top), Point(left + width, top + height), BLUE, 3*THICKNESS);
// Get the label for the class name and its confidence.
string label = format("%.2f", confidences[idx]);
label = class_name[class_ids[idx]] + ":" + label;
// Draw class labels.
draw_label(input_image, label, left, top);
//cout<<"The Value is "<<label;
//cout<<endl;
}
return input_image;
}
int main()
{
vector<string> class_list;
ifstream ifs("/Users/admin/Documents/C++/First/obj.names");
string line;
while (getline(ifs, line))
{
class_list.push_back(line);
}
// Load image.
Mat frame;
frame = imread("/Users/admin/Documents/C++/First/test.jpg");
// Load model.
Net net;
net = readNet("/Users/admin/Documents/C++/First/my.onnx");
vector<Mat> detections;
detections = pre_process(frame, net);
Mat img = post_process(frame, detections, class_list);
//Mat img = post_process(frame.clone(), detections, class_list);
// Put efficiency information.
// The function getPerfProfile returns the overall time for inference(t) and the timings for each of the layers(in layersTimes)
vector<double> layersTimes;
double freq = getTickFrequency() / 1000;
double t = net.getPerfProfile(layersTimes) / freq;
string label = format("Inference time : %.2f ms", t);
putText(img, label, Point(20, 40), FONT_FACE, FONT_SCALE, RED);
imshow("Output", img);
waitKey(0);
return 0;
}
The photos I use are 640x480. I played around with the size of the photo, thinking it might be related, but the same problem persisted.
The Yolov5 output format is xyxy as can be seen here:
https://github.com/ultralytics/yolov5/blob/bfa1f23045c7c4136a9b8ced9d6be8249ed72692/detect.py#L161
Not xywh as you are assuming in your code

How to rotate an image without using OpenCV functions? (using Linear, Qubic interpolation)

I am trying to rotate an image without using the OpenCV function.
I want to do it pixel by pixel with interpolation (nearest neighbors & linear & cubic) and later I would like to do it with a rotation matrix.
Problems:
Can't understand how to implement the interpolations. Even one example with the Qubic will help me.
for some reason the left pixels in the original image are sent to the right side in the rotated image and it seems not right for the rotation (should be black pixels).
Add an extra option (but not a must) to rotate the image from the center of the image. (and not from (0,0) which is the top left of the image by default)
The original image:
My code: (AFTER UPDATE 1)
#include <iostream>
#include <math.h>
#include "opencv2/opencv.hpp"
using namespace std;
enum interpolation_type{
INTERPOLATION_CUBIC,
INTERPOLATION_LINEAR,
INTERPOLATION_NEAREST_NEIGHBOR
};
void Interpolation_Calculator(const cv::Point& srcPixel,cv::Point2i& dstPixel, interpolation_type type){
// The origin pixels for the currPixel in the newImage depends on the interpolation type
int originX = 0;
int originY = 0;
if(type == INTERPOLATION_NEAREST_NEIGHBOR)
{
originX = (int)round(srcPixel.x);
originY = (int)round(srcPixel.y);
}
else if(type == INTERPOLATION_LINEAR){
}
else if (type == INTERPOLATION_CUBIC){
}
dstPixel.x = originX;
dstPixel.y = originY;
}
void RotationFunction(const cv::Mat& src,cv::Mat& dst, int angle, interpolation_type type){
// The pixels in the new image we want to find right origin pixel for his value.
double rotatedX;
double rotatedY;
double toRadian = 3.141592653589/180;
for(int r=0;r<dst.rows;r++)
{
for(int c=0;c<dst.cols;c++)
{
rotatedX = r*cos(angle * toRadian) - c*sin(angle * toRadian);
rotatedY = r*sin(angle * toRadian) + c*cos(angle * toRadian);
cv::Point rotatedPixel(rotatedX,rotatedY);
cv::Point2i originPixel;
Interpolation_Calculator(rotatedPixel,originPixel,type);
//cv::Vec3b vector(0,0,0);
// Checking if the Interpolation calculations crossed the boundaries
if(originPixel.x < 0 || originPixel.x > src.cols - 1 || originPixel.y < 0 || originPixel.y > src.rows - 1)
dst.at<cv::Vec3b>(cv::Point(r, c)) = 0;
else { // In case everything is good
cv::Vec3b currPixel = src.at<cv::Vec3b>(originPixel);
dst.at<cv::Vec3b>(cv::Point(r, c)) = currPixel;
}
}
}
}
int main() {
cv::Mat img = cv::imread("../lion.jpeg");
cv::Mat rotatedImage(img.rows,img.cols,CV_8UC3);
// Rotating
RotationFunction(img,rotatedImage,25,INTERPOLATION_NEAREST_NEIGHBOR);
// End of Rotating
// Show the images
cv::imshow("window1",img);
cv::imshow("window2",rotatedImage);
cv::waitKey(0);
// End of Show the images
return 0;
}
Bad Output:

vtkResliceImageViewer get bounds image in view

Situation:
I'm using vtkresliceimageviewer to display the three MPR views, based on this example.
So I can rotate the cursors to generate a new view on all three screens.
Question:
I want to know the bounds of my image on the viewer, even after rotating some of the cursors.
obs
I tried to get the values from the imageActor and ask for my renderer positions, but this works only when I have no interaction from the other cursors.
Example for axial:
void UpdatePointWordToViewer(vtkRenderer* rend, double p[4])
{
rend->SetWorldPoint(p);
rend->WorldToDisplay();
rend->GetDisplayPoint(p);
}
void UpdateBoxAxial()
{
auto bounds = pMPR->GetViewer(2)->GetImageActor()->GetBounds();
auto ren = pMPR->GetViewer(2)->GetRenderer();
auto size = pMPR->GetViewer(2)->GetInteractor()->GetSize();
double pIni1[]{ 0,0,0,1 };
double pIni2[]{ 0,0,0,1 };
double pIni3[]{ 0,0,0,1 };
double pIni4[]{ 0,0,0,1 };
double pConvert1[]{ 0,0,0 };
double pConvert2[]{ 0,0,0 };
//check the bounds
pIni1[0] = bounds[0];
pIni1[1] = bounds[3];
pIni1[2] = bounds[4];
pIni2[0] = bounds[1];
pIni2[1] = bounds[3];
pIni2[2] = bounds[4];
pIni3[0] = bounds[0];
pIni3[1] = bounds[2];
pIni3[2] = bounds[4];
pIni4[0] = bounds[1];
pIni4[1] = bounds[2];
pIni4[2] = bounds[4];
//convert the points for viewer coordinates
UpdatePointWordToViewer(ren, pIni1);
UpdatePointWordToViewer(ren, pIni2);
UpdatePointWordToViewer(ren, pIni3);
UpdatePointWordToViewer(ren, pIni4);
//P1
if (pIni1[0] < pIni3[0])
pConvert1[0] = pIni1[0];
else
pConvert1[0] = pIni3[0];
if (pIni3[1] < pIni4[1])
pConvert1[1] = pIni3[1];
else
pConvert1[1] = pIni4[1];
//P2
if (pIni2[0] > pIni4[0])
pConvert2[0] = pIni2[0];
else
pConvert2[0] = pIni4[0];
if (pIni1[1] > pIni2[1])
pConvert2[1] = pIni1[1];
else
pConvert2[1] = pIni2[1];
}
So I know the minimum point (Left - Down) and the maximum point (Right - Top)

Why ball1.boundingrect.center returns the same value as ball2.boundingrect.center?

I'm programming a physis simulation with circles.
Ball.cpp Code:
Ball::Ball()
{
angle = 0;
setRotation(angle);
//set the speed
speed = 5;
double StartX = 720;
double StartY = 80;
StartX = (qrand() % 800);
StartY = (qrand() % 400);
radius = 40;
setTransformOriginPoint(radius,radius);
setPos (StartX,StartY);
}
QRectF Ball::boundingRect() const
{
return QRect(0,0,2*radius,2*radius);
}
bool Ball:: circCollide(QList <QGraphicsItem *> items) {
QPointF c1 = mapToParent(this->boundingRect().center());
foreach (QGraphicsItem * t, items) {
Ball * CastBall = dynamic_cast<Ball *>(t);
if(CastBall)
{
QPointF t1 = mapToScene(CastBall->boundingRect().center());
double distance = QLineF(c1,t1).length();
double radius1 = this->boundingRect().width() / 2;
double radius2 = CastBall->boundingRect().width() / 2;
double radii = radius1 + radius2;
if ( distance <= radii )
{
// qDebug() << "true collision";
return true;
}
}
}
// qDebug() << "false collision";
return false;
}
I've got the problem that this string of code returns always the same values for the position of the center for both objects, (t1.x == c1.x , t1.y == c1.y) but this == CastBall returns false, so it wasn't the same object, it just has the same coordinates for the centerpoint of the boundingRect.
The coordinates are already equal before this function is called and that for all 3 objects I generate, although the sets always have a different value.
First I thought it was a problem because boundingRect is defined as a const, so I made this function in my class
QRectF Ball:: centerRect()
{
return QRect(0,0,2*radius,2*radius);
}
and just replaced every use of boundingRect with it (was no problem since I already cast it in the method), but it still returned the same value for both centers.
Im really at my wits end with this one and hope to find some help.
The problem was following: the center of the bounding rectangle was not mapped to the coordinates of the ball. Following statement should work:
mapToScene(mapToItem(castBall, castBall->boundingRect().center()));

World to screen space coordinates in OpenSceneGraph

So I've got a class Label that inherits from osg::Geode which I draw in the world space in OpenSceneGraph. After displaying each frame, I then want to read the screen space coordinates of
each Label, so I can find out how much they overlap in the screen space. To this end, I created a class ScreenSpace which should calculate this (the interesting function is calc_screen_coords.)
I wrote a small subroutine that dumps each frame with some extra information, including the ScreenSpace box which represents what the program thinks the screen space coordinates are:
Now in the above picture, there seems to be no problem; but if I rotate it to the other side (with my mouse), then it looks quite different:
And that is what I don't understand.
Is my world to screen space calculation wrong?
Or am I getting the wrong BoundingBox from the Drawable?
Or maybe it has something to do with the setAutoRotateToScreen(true) directive that I give the osgText::Text object?
Is there a better way to do this? Should I try to use a Billboard instead? How would I do that though? (I tried and it totally didn't work for me — I must be missing something...)
Here is the source code for calculating the screen space coordinates of a Label:
struct Pixel {
// elided methods...
int x;
int y;
}
// Forward declarations:
pair<Pixel, Pixel> calc_screen_coords(const osg::BoundingBox& box, const osg::Camera* cam);
void rearange(Pixel& left, Pixel& right);
class ScreenSpace {
public:
ScreenSpace(const Label* label, const osg::Camera* cam)
{
BoundingBox box = label->getDrawable(0)->computeBound();
tie(bottom_left_, upper_right_) = calc_screen_coords(box, cam);
rearrange(bottom_left_, upper_right_);
}
// elided methods...
private:
Pixel bottom_left_;
Pixel upper_right_;
}
pair<Pixel, Pixel> calc_screen_coords(const osg::BoundingBox& box, const osg::Camera* cam)
{
Vec4d vec (box.xMin(), box.yMin(), box.zMin(), 1.0);
Vec4d veq (box.xMax(), box.yMax(), box.zMax(), 1.0);
Matrixd transmat
= cam->getViewMatrix()
* cam->getProjectionMatrix()
* cam->getViewport()->computeWindowMatrix();
vec = vec * transmat;
vec = vec / vec.w();
veq = veq * transmat;
veq = veq / veq.w();
return make_pair(
Pixel(static_cast<int>(vec.x()), static_cast<int>(vec.y())),
Pixel(static_cast<int>(veq.x()), static_cast<int>(veq.y()))
);
}
inline void swap(int& v, int& w)
{
int temp = v;
v = w;
w = temp;
}
inline void rearrange(Pixel& left, Pixel& right)
{
if (left.x > right.x) {
swap(left.x, right.x);
}
if (left.y > right.y) {
swap(left.y, right.y);
}
}
And here is the construction of Label (I tried to abridge it a little):
// Forward declaration:
Geometry* createLeader(straph::Point pos, double height, Color color);
class Label : public osg::Geode {
public:
Label(font, fontSize, text, color, position, height, margin, bgcolor, leaderColor)
{
osgText::Text* txt = new osgText::Text;
txt->setFont(font);
txt->setColor(color.vec4());
txt->setCharacterSize(fontSize);
txt->setText(text);
// Set display properties and height
txt->setAlignment(osgText::TextBase::CENTER_BOTTOM);
txt->setAutoRotateToScreen(true);
txt->setPosition(toVec3(position, height));
// Create bounding box and leader
typedef osgText::TextBase::DrawModeMask DMM;
unsigned drawMode = DMM::TEXT | DMM::BOUNDINGBOX;
drawMode |= DMM::FILLEDBOUNDINGBOX;
txt->setBoundingBoxColor(bgcolor.vec4());
txt->setBoundingBoxMargin(margin);
txt->setDrawMode(drawMode);
this->addDrawable(txt);
Geometry* leader = createLeader(position, height, leaderColor);
this->addDrawable(leader);
}
// elided methods and data members...
}
Geometry* createLeader(straph::Point pos, double height, Color color)
{
Geometry* leader = new Geometry();
Vec3Array* array = new Vec3Array();
array->push_back(Vec3(pos.x, pos.y, height));
array->push_back(Vec3(pos.x, pos.y, 0.0f));
Vec4Array* colors = new Vec4Array(1);
(*colors)[0] = color.vec4();
leader->setColorArray(colors);
leader->setColorBinding(Geometry::BIND_OVERALL);
leader->setVertexArray(array);
leader->addPrimitiveSet(new DrawArrays(PrimitiveSet::LINES, 0, 2));
LineWidth* lineWidth = new osg::LineWidth();
lineWidth->setWidth(2.0f);
leader->getOrCreateStateSet()->setAttributeAndModes(lineWidth, osg::StateAttribute::ON);
return leader;
}
Any pointers or help?
I found a solution that works for me, but is also unsatisfying, so if you have a better solution, I'm all ears.
Basically, I take different points from the Label that I know will be at certain points,
and I calculate the screen space by combining this. For the left and right sides, I take
the bounds of the regular bounding box, and for the top and bottom, I calculate it with the
center of the bounding box and the position of the label.
ScreenSpace::ScreenSpace(const Label* label, const osg::Camera* cam)
{
const Matrixd transmat
= cam->getViewMatrix()
* cam->getProjectionMatrix()
* cam->getViewport()->computeWindowMatrix();
auto topixel = [&](Vec3 v) -> Pixel {
Vec4 vec(v.x(), v.y(), v.z(), 1.0);
vec = vec * transmat;
vec = vec / vec.w();
return Pixel(static_cast<int>(vec.x()), static_cast<int>(vec.y()));
};
// Get left right coordinates
vector<int> xs; xs.reserve(8);
vector<int> ys; ys.reserve(8);
BoundingBox box = label->getDrawable(0)->computeBound();
for (int i=0; i < 8; i++) {
Pixel p = topixel(box.corner(i));
xs.push_back(p.x);
ys.push_back(p.y);
};
int xmin = *min_element(xs.begin(), xs.end());
int xmax = *max_element(xs.begin(), xs.end());
// Get up-down coordinates
int ymin = topixel(dynamic_cast<const osgText::Text*>(label->getDrawable(0))->getPosition()).y;
int center = topixel(box.center()).y;
int ymax = center + (center - ymin);
bottom_left_ = Pixel(xmin, ymin);
upper_right_ = Pixel(xmax, ymax);
z_ = distance_from_camera(label, cam);
}