1

I am using the probabilistic hough transform of OpenCV via OpenCV's Java wrapper. These are stored in a Mat though and while the approach of an already existing answer works, I discovered that there is a Converters class specifically for converting Mats into Collections back and forth.

However, all potentially suitable converters expect the Mat in question to only have 1 column and multiple rows. The Mat „returned” by HoughLinesP however has the resulting points stored in a single row, one line per column storing a double[] per „pixel” in the Mat with 4 components. This results in this exception:

Caused by: java.lang.IllegalArgumentException: CvType.CV_32SC2 != m.type() ||  m.cols()!=1
    Mat [ 1*4*CV_32SC4, isCont=true, isSubmat=false, nativeObj=0x7fe913e98890, dataAddr=0x7fe913ca7e50 ]
    at org.opencv.utils.Converters.Mat_to_vector_Mat(Converters.java:258)
    at org.opencv.utils.Converters.Mat_to_vector_vector_Point2f(Converters.java:516)

Are the OpenCV Converters meant for what I am trying to use them for? Is there a better way to do that or is my only option to tediously read every pixel in the resulting Mat myself?

Community
  • 1
  • 1
phdoerfler
  • 470
  • 6
  • 19

1 Answers1

0

Since OpenCV does not have it's own data class for Lines I guess one workaround would be to create a class similar to MatOfRect to do the conversion. This would look sth. like:

Line.java

public class Line
{
    public final Point p1;
    public final Point p2;
    
    public Line(double p1x, double p1y, double p2x, double p2y)
    {
        this.p1 = new Point(p1x, p1y);
        this.p2 = new Point(p2x, p2y);
    }
    
    
    public Line(Point p1, Point p2)
    {
        this.p1 = p1;
        this.p2 = p2;
    }
    
    
    public Line()
    {
        this(new Point(0, 0), new Point(0, 0));
    }
    
    
    public Line(double[] vals)
    {
        this();
        set(vals);
    }
    
    
    public void set(double[] vals)
    {
        if (vals != null)
        {
            p1.x = vals.length > 0 ? vals[0] : 0;
            p1.y = vals.length > 1 ? vals[1] : 0;
            p2.x = vals.length > 3 ? vals[2] : 0;
            p2.y = vals.length > 4 ? vals[3] : 0;
        } else
        {
            p1.x = 0;
            p1.y = 0;
            p2.x = 0;
            p2.y = 0;
        }
    }
    
    
    @Override
    public Line clone()
    {
        return new Line(p1.clone(), p2.clone());
    }
    
    
    @Override
    public int hashCode()
    {
        final int prime = 31;
        int result = 1;
        long temp;
        temp = Double.doubleToLongBits(p1.x);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(p1.y);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(p2.x);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(p2.y);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
    
    
    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
            return true;
        if (!(obj instanceof Line))
            return false;
        Line it = (Line) obj;
        return p1.equals(it.p1) && p2.equals(it.p2);
    }
    
    
    @Override
    public String toString()
    {
        return "{" + p1.x + ", " + p1.y + ", " + p2.x + ", " + p2.y + "}";
    }
    
}

MatOfLine.java

public class MatOfLine extends Mat
{
    // 32SC4
    private static final int _depth = CvType.CV_32S;
    private static final int _channels = 4;
    
    public MatOfLine()
    {
        super();
    }
    
    
    protected MatOfLine(long addr)
    {
        super(addr);
        if (!empty() && checkVector(_channels, _depth) < 0)
            throw new IllegalArgumentException("Incompatible Mat");
        // FIXME: do we need release() here?
    }
    
    
    public static MatOfLine fromNativeAddr(long addr)
    {
        return new MatOfLine(addr);
    }
    
    
    public MatOfLine(Mat m)
    {
        super(m, Range.all());
        if (!empty() && checkVector(_channels, _depth) < 0)
            throw new IllegalArgumentException("Incompatible Mat");
        // FIXME: do we need release() here?
    }
    
    
    public MatOfLine(Line... a)
    {
        super();
        fromArray(a);
    }
    
    
    public void alloc(int elemNumber)
    {
        if (elemNumber > 0)
            super.create(elemNumber, 1, CvType.makeType(_depth, _channels));
    }
    
    
    public void fromArray(Line... a)
    {
        if (a == null || a.length == 0)
            return;
        int num = a.length;
        alloc(num);
        int[] buff = new int[num * _channels];
        for (int i = 0; i < num; i++)
        {
            Line l = a[i];
            buff[_channels * i + 0] = (int) l.p1.x;
            buff[_channels * i + 1] = (int) l.p1.y;
            buff[_channels * i + 2] = (int) l.p2.x;
            buff[_channels * i + 3] = (int) l.p2.y;
        }
        put(0, 0, buff); // TODO: check ret val!
    }
    
    
    public Line[] toArray()
    {
        int num = (int) total();
        Line[] a = new Line[num];
        if (num == 0)
            return a;
        int[] buff = new int[num * _channels];
        get(0, 0, buff); // TODO: check ret val!
        for (int i = 0; i < num; i++)
            a[i] = new Line(buff[i * _channels], buff[i * _channels + 1], buff[i * _channels + 2],
                    buff[i * _channels + 3]);
        return a;
    }
    
    
    public void fromList(List<Line> lr)
    {
        Line[] ap = lr.toArray(new Line[0]);
        fromArray(ap);
    }
    
    
    public List<Line> toList()
    {
        Line[] ar = toArray();
        return Arrays.asList(ar);
    }

}

And then use it like this:

Mat mYuv = new Mat();
Mat mRgba = new Mat();
Mat thresholdImage = new Mat(getFrameHeight() + getFrameHeight() / 2, getFrameWidth(), CvType.CV_8UC1);
mYuv.put(0, 0, data);
Imgproc.cvtColor(mYuv, mRgba, Imgproc.COLOR_YUV420sp2RGB, 4);
Imgproc.cvtColor(mRgba, thresholdImage, Imgproc.COLOR_RGB2GRAY, 4);
Imgproc.Canny(thresholdImage, thresholdImage, 80, 100, 3);
Mat lines = new Mat();
int threshold = 50;
int minLineSize = 20;
int lineGap = 20;

Imgproc.HoughLinesP(thresholdImage, lines, 1, Math.PI / 180, threshold, minLineSize, lineGap);

List<Line> convertedLines = (new MatOfLine(lines)).toList();

for (final Line line : convertedLines)
{
    Imgproc.line(mRgba, line.p1, line.p2, new Scalar(255, 0, 0), 3);
}

Bitmap bmp = Bitmap.createBitmap(getFrameWidth(), getFrameHeight(), Bitmap.Config.ARGB_8888);

if (Utils.matToBitmap(mRgba, bmp))
    return bmp;
enwi
  • 67
  • 1
  • 2
  • 8