c++cimg

Mirror an image using the CImg?


The title is pretty self-explanatory, but I will stress that I am a beginner at c++ and especially when it comes down to the CImg library. Here's the code I have so far and I tried experimenting with the flipped_idx (which didn't work when incorporated into the code) but I don't think I'm heading in the right direction. Or maybe I am, any help would be greatly appreciated!

I'm inputting the first two images below and merging them into one image.

enter image description here

enter image description here

Here's the merged image that I am trying to mirror on the y-axis.

enter image description here

#include <iostream>
#include "CImg.h"

using namespace std;
using namespace cimg_library;

const int imgscale = 400;

int main() {

CImg<unsigned char> player("input/player.bmp");

CImgDisplay green_disp(player, "Original 'player.bmp'");
green_disp.resize(imgscale, imgscale, true);
green_disp.move(10, 50);


CImg<unsigned char> bg("input/forest.bmp");

CImgDisplay bg_disp(bg, "Original 'forest.bmp'");
bg_disp.resize(imgscale, imgscale, true);
bg_disp.move(20 + imgscale, 50);

CImg<unsigned char> merged(player.width(), player.height(),1,3,0);
int w = player.width();
int h = player.height();
int imglen = w*h;
const CImg<float>
    flipped_idx = merged.get_mirror('y');


for (int i = 0; i < h; ++i) {
    for (int j = 0; j < w; ++j) {
        int idx = j + i*w;


        unsigned char colorR = player[idx];
        unsigned char colorG = player[idx + imglen];
        unsigned char colorB = player[idx + imglen * 2];

        if (colorG > 215 && colorR < 255) {
            //Background
            merged[idx] = bg[idx]; //red
            merged[idx + imglen] = bg[idx + imglen]; //green
            merged[idx + imglen * 2] = bg[idx + imglen * 2]; //blue
        }
        else {
            //Foreground
            merged[idx] = player[idx]; //red
            merged[idx + imglen] = player[idx + imglen]; //green
            merged[idx + imglen * 2] = player[idx + imglen * 2]; //blue
        }

    }
}

CImgDisplay merged_disp(merged, "Merged image");
merged_disp.resize(imgscale, imgscale,true); //change size
merged_disp.move(30 + imgscale*2, 50); //place it nicely on screen.
merged.save("output/merged.bmp");

Solution

  • If I try and stick to your code as closely as possible, but discard all the display stuff, I get this:

    #include <iostream>
    #include "CImg.h"
    
    using namespace std;
    using namespace cimg_library;
    
    const int imgscale = 400;
    
    int main() {
    
    CImg<unsigned char> player("player.bmp");
    CImg<unsigned char> bg("forest.bmp");
    
    CImg<unsigned char> merged(player.width(), player.height(),1,3,0);
    int w = player.width();
    int h = player.height();
    int imglen = w*h;
    CImg<unsigned char> result;
    
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            int idx = j + i*w;
    
            unsigned char colorR = player[idx];
            unsigned char colorG = player[idx + imglen];
            unsigned char colorB = player[idx + imglen * 2];
    
            if (colorG > 215 && colorR < 255) {
                //Background
                merged[idx] = bg[idx]; //red
                merged[idx + imglen] = bg[idx + imglen]; //green
                merged[idx + imglen * 2] = bg[idx + imglen * 2]; //blue
            }
            else {
                //Foreground
                merged[idx] = player[idx]; //red
                merged[idx + imglen] = player[idx + imglen]; //green
                merged[idx + imglen * 2] = player[idx + imglen * 2]; //blue
            }
        }
    }
    
    result = merged.get_mirror('y');
    result.save("merged.bmp");
    }
    

    enter image description here


    If I was coding it, I would probably go with something more like this:

    #include <iostream>
    #include "CImg.h"
    
    using namespace std;
    using namespace cimg_library;
    
    int main() {
    
       CImg<unsigned char> player("player.bmp");
       CImg<unsigned char> bg("forest.bmp");
       CImg<unsigned char> merged(player.width(), player.height(),1,3,0);
       CImg<unsigned char> result;
    
       // Extract Green channel and make into mask by thresholding
       CImg<unsigned char> mask = player.get_channel(1).threshold(215);
       mask.save("mask.bmp");
    
       // Select background or foreground according to mask
       merged = bg.mul(mask) + player.mul(1-mask);
       merged.save("merged.bmp");
    
       // Mirror and save
       result = merged.get_mirror('y');
       result.save("result.bmp");
    }
    

    Just FYI, the mask looks like this:

    enter image description here