Ask Your Question

Split a Mat into parts, based on each containing three colors?

asked 2018-02-08 07:10:01 -0500

antithing gravatar image

updated 2018-02-08 09:29:32 -0500

I am looking at speeding up an alpha matting algorithm. To do this I need to cut a mat of this image:

image description

into the smallest possible sections, where each section contains all three of the possible colors. (the alpha matting algorithm requires all three to compute the matte).

It will not always be the same image, how can i automatically chop up a Mat into submats based on all three colors being present?

So what I have now is:

image description

But the matte algorithm fails where there is only black and gray, or only white and gray. I need every color inside every section. I guess something like this would work for this image:

image description

But every image will be different, so I will need to work it out based on color.

thank you.

edit retag flag offensive close merge delete


I don't understand what you want exactly.

split is to split channels (BGR).

if you want only white pixels in img then use a mask :

Mat maskWhite = img == 255;
Mat maskGray = img == 127;
Mat maskBlack= img == 0;
LBerger gravatar imageLBerger ( 2018-02-08 07:43:07 -0500 )edit

Hi, thanks for your reply. Perhaps split is the wrong word. I need to create sub mats from the image, or ROI. Each one as small as possible, while containing some white, some black, and some gray pixels.So rather than creating ROI with even spacing, i need to work out how best to cut the image up, giving me the maximum number of pieces, each containing all three colors. Does that make more sense?

antithing gravatar imageantithing ( 2018-02-08 08:46:09 -0500 )edit

Please add some sample Image for your desired output!

Balaji R gravatar imageBalaji R ( 2018-02-08 09:19:35 -0500 )edit

Done! thank you.

antithing gravatar imageantithing ( 2018-02-08 09:29:41 -0500 )edit

Is it necessary for All your Squares to be in the same size?

Balaji R gravatar imageBalaji R ( 2018-02-08 09:37:39 -0500 )edit

It is not an opencv problem but an image processing problem. I don't think you can ignore this page where you find some source codes to solve this problem

LBerger gravatar imageLBerger ( 2018-02-08 09:42:25 -0500 )edit

Nope! the only specification is that every color is present.

antithing gravatar imageantithing ( 2018-02-08 09:43:28 -0500 )edit

1 answer

Sort by ยป oldest newest most voted

answered 2018-02-08 11:41:35 -0500

updated 2018-02-08 22:07:10 -0500


I think it is better to fit a Triangle than a Square for your use case.Hope this gives you some rough idea! We can partition the Alpha mask based on these initial cuts. I will add the later part in sometime.

#include <iostream>
#include "opencv2/opencv.hpp"

using namespace cv;
using namespace std;

void Erode(InputArray mSrc, OutputArray mDst, int erosion_size, int erosion_elem)
    int erosion_type = 0;
    if (erosion_elem == 0){ erosion_type = MORPH_RECT; }
    else if (erosion_elem == 1){ erosion_type = MORPH_CROSS; }
    else if (erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }

    Mat element = getStructuringElement(erosion_type,
        Size(2 * erosion_size + 1, 2 * erosion_size + 1),
        Point(erosion_size, erosion_size));

    /// Apply the erosion operation
    erode(mSrc, mDst, element);

void Dilate(InputArray mSrc, OutputArray mDst, int dilate_size, int dilate_elem)
    int dilate_type = 0;
    if (dilate_elem == 0){ dilate_type = MORPH_RECT; }
    else if (dilate_elem == 1){ dilate_type = MORPH_CROSS; }
    else if (dilate_elem == 2) { dilate_type = MORPH_ELLIPSE; }

    Mat element = getStructuringElement(dilate_type,
        Size(2 * dilate_size + 1, 2 * dilate_size + 1),
        Point(dilate_size, dilate_size));

    /// Apply the erosion operation
    dilate(mSrc, mDst, element);

int main(int argc, char* argv[])
    string FileName_S = "Input.png";

    Mat mSource= imread(FileName_S,0), 

    if (mSource.empty())
        cout << "[Error] Invalid Input Image!";
        return 0;

    //Source Image
    imshow("Input Image", mSource);

image description

    //Extract the Alpha Mask that we are interested in
    inRange(mSource, 128, 128, mAlphaMat);

    //Extract the Foreground Mask too
    inRange(mSource, 255, 255, mForegroundMask);

    //Choose the Size of the Intersection Area
    const int SIZE_WIDTH = 5;

    //Grow the White region by Dilating the Alpha Mask
    Dilate(mAlphaMat, mAlphaMat, SIZE_WIDTH, 1);

    imshow("Alpha Mask + Dilate", mAlphaMat);

image description

    //Just for Visualisation purpose
    mSource.copyTo(mResult, mAlphaMat);
    cvtColor(mResult, mResult, COLOR_GRAY2BGR);

    //Find the Centre of the Foreground Mask to Start Partition in a Circle
    Moments Moments = moments(mForegroundMask);
    Point Centre(int(Moments.m10 / Moments.m00), int(Moments.m01 / Moments.m00));
    Rect bounds(0, 0, mResult.cols, mResult.rows);

    for (int Angle = 0; Angle<360; Angle += 20)
        //Find another point in the circle with some offset! We just need the direction!
        Point Point2(Centre.x + sin(Angle*CV_PI / 180) * 500, Centre.y + cos(Angle*CV_PI / 180) * 500);

        //Iterate through the Line till the Image Boundary
        LineIterator Line_Itr(mResult, Centre, Point2, 8);

        //Draw the Line at each step till it reaches Image Boundary
        while (bounds.contains(Line_Itr.pos()) && (Line_Itr.pos().x>0 &&Line_Itr.pos().y>0))
  <Vec3b>(Line_Itr.pos()) = Vec3b(0, 255, 0);

    imshow("Result", mResult);

image description


edit flag offensive delete link more


Thank you! After more thought, I actually need to stick with squares, so i can process each as a separate Mat, then re-assemble into one. I will definitely use this as a starting point tho. Thank you again!

antithing gravatar imageantithing ( 2018-02-09 03:46:51 -0500 )edit

Question Tools

1 follower


Asked: 2018-02-08 07:10:01 -0500

Seen: 508 times

Last updated: Feb 08 '18