Trying to remove background and make it transparent in c++, using magick++ - c++

I am having an image "objects.png" with a red background and I'm trying to make the background transparent. The code is straight forward but somehow I am not able to get the desired result. I am quite new to this ImageMagick business and this is my first program using Magick++. So, it would be great if you can explain things in detail. Thanks in advance. Code goes like this,
#include <iostream>
#include <Magick++.h>
using namespace std;
using namespace Magick;
int main(){
Image my_image("objects.png");
Color bg_color = my_image.pixelColor(0,0);
Color new_bg_color(0, MaxRGB, 0, MaxRGB);
for (int i=0;i<my_image.columns();i++){
for (int j=0;j<my_image.rows();j++){
//cout<<"(i,j) : ("<<i<<","<<j<<")\n";
if (my_image.pixelColor(i,j) == bg_color){
my_image.pixelColor(i,j,new_bg_color);
}
}
}
my_image.write("new_objects.png");
}
Image objects.png is
and I'm getting this as output

I think there is a Magick::Image.transparent method that should handle transparency assignment.
#include <iostream>
#include <Magick++.h>
using namespace std;
using namespace Magick;
int main(){
Image my_image("objects.png");
Color bg_color = my_image.pixelColor(0,0);
my_image.transparent(bg_color);
my_image.write("new_objects.png");
}
Edit
To allow the Magick::Color's opacity to be respected. You need to enable the alpha channel of the image by setting Magick::Image.matte, or Magick::Image.opacity attributes.
#include <iostream>
#include <Magick++.h>
using namespace std;
using namespace Magick;
int main(){
Image my_image("objects.png");
Color bg_color = my_image.pixelColor(0,0);
Color new_bg_color(0, MaxRGB, 0, MaxRGB);
my_image.matte(true); // or my_image.opacity();
for (int i=0;i<my_image.columns();i++){
for (int j=0;j<my_image.rows();j++){
if (my_image.pixelColor(i,j) == bg_color){
my_image.pixelColor(i,j,new_bg_color);
}
}
}
my_image.write("new_objects.png");
}

Related

vtk example from vtk book does not work with 9.1

In the VTK book at page 63 there is an example which I pasted below.
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkConeSource.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
int main(int, char* [])
{
vtkNew<vtkNamedColors> colors;
vtkNew<vtkConeSource> cone;
cone->SetHeight(3.0);
cone->SetRadius(1.0);
cone->SetResolution(10);
vtkNew<vtkPolyDataMapper> coneMapper;
coneMapper->SetInputConnection(cone->GetOutputPort());
vtkNew <vtkActor> coneActor;
coneActor->SetMapper(coneMapper);
vtkNew <vtkRenderer > ren1;
ren1->AddActor(coneActor);
ren1->SetBackground(
colors->GetColor3d("MidnightBlue").GetData());
vtkNew <vtkRenderWindow > renWin;
renWin->AddRenderer(ren1);
renWin->SetSize(300, 300);
for (auto i = 0; i < 360; ++i)
{
// render the image
renWin->Render();
// rotate the active camera by one degree
ren1->GetActiveCamera()->Azimuth(1);
}
return EXIT_SUCCESS;
}
I have downloaded and compiled VTK 9.1 on my Windows 10 machine. I tried to run the example as it is and it crashes on the following line:
ren1->SetBackground(
colors->GetColor3d("MidnightBlue").GetData());
The culprit is actually the call to colors->GetColor3d("MidnightBlue").GetData(). Since I do not care what color the background is at this very early point, I replaced the crashing line with
ren1->SetBackground(0.20, 0.20, 0.20);
Now it runs to the end, but no window shows up. My expectation was that a window would pop up with a rotating cone inside. No such luck. Can anybody point me in the right direction? What am I doing wrong?

When implmenting shapes using structures and classes C++

Hi guys so I'm trying to draw a tower by implementing shapes using structures and classes in C++. Below is what I'm trying to draw using 6 different shapes: point, shape, rectangle, circle, triangle, square. I have to create .h and .cpp file for each shapes and I never really understood what to put on each .h and .cpp files for each shapes. I will include what I have so far on my main.cpp and I just would like to know if I'm going in the right direction as well as what kind of information/code would I have to write on each .h and .cpp file for each shapes.
Picture of what I'm trying to draw
main.cpp
#include <iostream>
#include "point.h"
#include "shape.h"
#include "rectangle.h"
#include "square.h"
#include "triangle.h"
#include "circle.h"
using namespace std;
int main(){
//create objects of the shapes
Rectangle r, r1;
Square s;
Triangle t;
Circle c, c1;
//first rectangle
r.setLineType('*');
r.moveBy(5, 5); //x and y coordinates
r.setHeight(5);
r.setWidth(20);
r.computeArea();
r.draw(); // draw a rectangle in 2D array
auto firstRectangleArea = r.computeArea();
auto firstRectangleCircumference = r.computerCircumference();
//second rectangle
r1.setLineType('*');
r1.moveBy(10, 0);
r1.setHeight(20);
r1.setWidth(5);
r1.computeArea();
r1.draw(); // draw a rectangle in 2D array
auto secondRectangleArea = r1.computeArea();
auto secondRectangleCircumference = r1.computeCircumference();
//triangle
t.setLineType('*');
t.moveBy(15, 0);
t.setHeight(5);
t.setBase(5);
//first circle
c.moveBy(15, 0);
c.setRadius(2);
auto firstCircleArea = c.computeArea();
auto firstCircleCircumference = c.computeCircumference();
//second circle
c1.setLineType('*');
c1.moveBy(6, 0);
c1.setRadius(4);
auto secondCircleArea = c1.computeArea();
auto secondCircleCircumference = c1.computeCircumference();

The graphics.h library when used , shows objects inverted and also inverts the coordinates too

I tried to write a code to draw a triangle with its base facing downwards, using the following program:
#include<graphics.h>
#include<conio.h>
using namespace std;
int main()
{
initwindow(400,400,"Triangle");
line(100,100,200,300);
line(200,300,300,100);
line(100,100,300,100);
getch();
return 0;
}
But this gave the wrong output ^^
Whereas when I inverted the coordinates and created a mirror of them, then the triangle was drawn correctly
#include<graphics.h>
#include<conio.h>
using namespace std;
int main()
{
initwindow(400,400,"Triangle");
line(100,300,200,100);
line(200,100,300,300);
line(300,300,100,300);
getch();
return 0;
}
How do I fix this bug?
It seems that you are using a library which supports the Borland Graphics Interface (BGI). In BGI the origin is the top left of the screen, as S.E.C.H surmised. Here some documentation:
Each pixel is specified by its row and column position where coordinates (0, 0) corresponds to the pixel in the upper-left corner of the window and (width-1, height-1) corresponds to the pixel in the lower-right corner of the window.
http://dsearls.org/courses/C122CompSci/Graphics/GraphicsIntro.htm

Shrink/Expand the outline of a polygon with holes

I want to expand/shrink a polygon with holes using boost::polygon. So to clarify that a bit, I have a single data structure
boost::polygon::polygon_with_holes_data<int> inPoly
where inPoly contains data that describe a rectangular outline and a triangle which forms the hole within this rectangle (in picture below this is the left, black drawing).
Now I want to
a) expand the whole stuff so that the rectangle becomes bigger and the hole becomes smaller (resulting in the red polygon in image below) or
b) shrink it so that the rectangle becomes smaller and the hole bigger (resulting in the green image below).
The corners don't necessarily need to be straight, the also can be rounded or somehow "rough".
My question: how can this be done using boost::polygon?
Thanks!
I answered this Expand polygons with boost::geometry?
And yes you can teach Boost Geometry to act on Boost Polygon types:
#include <boost/geometry/geometries/adapted/boost_polygon.hpp>
I came up with a test polygon like you described:
boost::polygon::polygon_with_holes_data<int> inPoly;
bg::read_wkt("POLYGON ((0 0,0 1000,1000 1000,1000 0,0 0),(100 100,900 100,500 700,100 100))", inPoly);
Now, apparently we can't just buffer on the adapted polygon, nor can we bg::assign or bg::convert directly. So, I came up with an ugly workaround of converting to WKT and back. And then you can do the buffer, and conver back similarly.
It's not very elegant, but it does work:
poly in;
bg::read_wkt(boost::lexical_cast<std::string>(bg::wkt(inPoly)), in);
Full Demo
Include SVG output:
Live On Coliru
#include <boost/polygon/polygon.hpp>
#include <boost/polygon/polygon_set_data.hpp>
#include <boost/polygon/polygon_with_holes_data.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/algorithms/buffer.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/adapted/boost_polygon.hpp>
#include <fstream>
namespace bp = boost::polygon;
namespace bg = boost::geometry;
using P = bp::polygon_with_holes_data<int>;
using PS = bp::polygon_set_data<int>;
using coordinate_type = bg::coordinate_type<P>::type;
int main() {
P inPoly, grow, shrink;
bg::read_wkt("POLYGON ((0 0,0 1000,1000 1000,1000 0,0 0),(100 100,900 100,500 700,100 100))", inPoly);
{
// define our boost geometry types
namespace bs = bg::strategy::buffer;
namespace bgm = bg::model;
using pt = bgm::d2::point_xy<coordinate_type>;
using poly = bgm::polygon<pt>;
using mpoly = bgm::multi_polygon<poly>;
// define our buffering strategies
using dist = bs::distance_symmetric<coordinate_type>;
bs::side_straight side_strategy;
const int points_per_circle = 12;
bs::join_round join_strategy(points_per_circle);
bs::end_round end_strategy(points_per_circle);
bs::point_circle point_strategy(points_per_circle);
poly in;
bg::read_wkt(boost::lexical_cast<std::string>(bg::wkt(inPoly)), in);
for (auto [offset, output_p] : { std::tuple(+15, &grow), std::tuple(-15, &shrink) }) {
mpoly out;
bg::buffer(in, out, dist(offset), side_strategy, join_strategy, end_strategy, point_strategy);
assert(out.size() == 1);
bg::read_wkt(boost::lexical_cast<std::string>(bg::wkt(out.front())), *output_p);
}
}
{
std::ofstream svg("output.svg");
using pt = bg::model::d2::point_xy<coordinate_type>;
boost::geometry::svg_mapper<pt> mapper(svg, 400, 400);
mapper.add(inPoly);
mapper.add(grow);
mapper.add(shrink);
mapper.map(inPoly, "fill-opacity:0.3;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
mapper.map(grow, "fill-opacity:0.05;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(shrink, "fill-opacity:0.05;fill:rgb(0,0,255);stroke:rgb(0,0,255);stroke-width:2");
}
}
The output.svg written:
More or less accidentally I found boost::polygon also provides a single function for that which is quite easy to use: boost::polygon::polygon_set_data offers a function resize() which is doing exactly what is described above. Using the additional, parameters corner_fill_arc and num_segments rounded corners can be created.
No idea why this function is located in boost::polygon::polygon_set_data and not in boost::polygon::polygon_with_holes_data which in my opinion would be the more logically place for such a function...

C++ Allegro: Program Crashes when I move the window

I Have built a C++ Allegro Map Editor. One of the requests was to have a log so I've put it in the console window for every move that is made... Problem now is that the console window is under the main window (Used GFX_AUTODETECT_WINDOWED), But whenever I try to move that window, it simply crashes the program.. I need to be able to move it and to move the console window to and come back to the map editor. Anybody has any ideas???
Here's the main of my code.
#include <allegro.h>
#include <string>
#include <sstream>
#include "Layout.h"
#include "System.h"
#include "Map.h"
#include <iostream>
#include <fstream>
using namespace std;
// Allegro Functions to stabilize speed
volatile long speed_counter = 0;
void increment_speed_counter() // A function to increment the speed counter
{speed_counter++; }
END_OF_FUNCTION(increment_speed_counter);
int main()
{
System system; // Initialising Allegro
system.Setup();
Map map1; // Creating default map
map1.createMap();
BITMAP *buffer = create_bitmap(24,45); // Double buffering
LOCK_VARIABLE(speed_counter); //Used to set the timer - which regulates the game's
LOCK_FUNCTION(increment_speed_counter);//speed.
install_int_ex(increment_speed_counter, BPS_TO_TIMER(8));//Set our BP
/*game looop */
while( !key[KEY_ESC] )
{
clear_bitmap(buffer); // Clear the contents of the buffer bitmap
while(speed_counter > 0)
{
if(mouse_b &1 ){ // On mouse click
map1.catchMouseEvent(mouse_x, mouse_y);
while(mouse_b & 1){}
}
speed_counter --;
}
rectfill(buffer,0,0,25,45,makecol(135,206,250));
textprintf_ex(buffer, map1.getLayout().getFont(), 0, 0, makecol(255, 255, 255), -1,"%d", map1.getRowVal());
textprintf_ex(buffer, map1.getLayout().getFont(), 0, 20, makecol(255, 255, 255), -1,"%d", map1.getColVal());
blit(buffer, screen, 0, 0, 970, 50, 100, 50);
}
/*Free memory after */
destroy_bitmap( buffer );
return 0;
allegro_exit();
}
END_OF_MAIN();
Also, it does happen that it randomly crashes by itself without moving the window. There is not a specific reason, it just crashes at random times.
Any ideas someone?
Without seeing all of the code, it's impossible to know why or where it's crashing. If you use a debugger it should be obvious what's happening. You should be responding to return codes. e.g., When you load or create a bitmap, make sure it's not NULL.
I'm not really sure what you are trying to do with such a smaller double buffer. Typically you create a single buffer the same size as the window. Note that Allegro 4 will only work properly if the screen width is a multiple of four. Also, you should call set_color_depth(desktop_color_depth()) (before setting the graphics mode) for maximum compatibility.