2
$\begingroup$

I have the image below and would like to isolate only the black square (on top of it are some brighter rings visible originating from an illumination lamp).

How can that be done?

enter image description here

$\endgroup$
3
  • $\begingroup$ IIs it this what you want? ImageTake[ Import["http://i.stack.imgur.com/QF8Wk.jpg"], {175, 1300}, {170, 1295}] or subtract the rings from the square? $\endgroup$ Apr 12, 2016 at 13:33
  • $\begingroup$ No ... not by hand ... this is trivial ... $\endgroup$
    – mrz
    Apr 12, 2016 at 13:42
  • $\begingroup$ that was my impression. Do you want to do several squares or what? your question as it stands is a bit unclear. $\endgroup$ Apr 12, 2016 at 14:11

2 Answers 2

3
$\begingroup$

In this case code below works, but it's sensitive to the second parameter of EdgeDetect:

Module[{img, poly},
 img = Import["https://i.stack.imgur.com/QF8Wk.jpg"];
 poly = First@
   MeshPrimitives[
    ConvexHullMesh[
     Cases[RegionIntersection @@@ 
       Subsets[Line /@ 
         ImageLines[EdgeDetect[img, 20], MaxFeatures -> 4], {2}], 
      Point[{p_}] :> p]], 2]; {poly, 
  HighlightImage[
   img, {EdgeForm@Directive[Thick, Green], FaceForm@None, poly}]}]
{ Polygon[
   {{104.701, 1285.21}, {113.932, 100.757}, {1291.24, 102.425}, {1288.73, 1283.54}}],

enter image description here

}

First this code finds four most dominant lines on the edge-detected image, then finds pairwise intersections of those lines, somewhat clumsily extracts corresponding points from the results, then builds a convex hull around them, and then extracts the result as a Polygon. There are surely somewhat different ways to do the same.

EDIT:

If you know your square is centered on the image and its view is a normal geometric projection of it, you can perform the reverse projection (which also does perspective correction) the following way:

With[{
  img = Import["https://i.stack.imgur.com/QF8Wk.jpg"],
  outdim = 1024},
 ImageTransformation[img, 
  Last@FindGeometricTransform[
    SortBy[Cases[
      RegionIntersection @@@ 
       Subsets[Line /@ 
         ImageLines[EdgeDetect[img, 20], MaxFeatures -> 4], {2}], 
      Point[{p_}] :> p], 
     ArcTan @@ (# - ImageDimensions@img/2) &],
    {{0, 0}, {outdim, 0}, {outdim, outdim}, {0, outdim}}],
  DataRange -> Full, PlotRange -> {{0, outdim}, {0, outdim}}]]

enter image description here

Here we find the line intersections, and sort them to NW, NE, SE, SW order, then find a projection of them to our target output image corners, and apply it to the image.

$\endgroup$
4
  • $\begingroup$ Thank you for your help. In general the square is not centered in the image. Do you have an idea how one can define the "best"? value (second parameter) in EdgeDetect? $\endgroup$
    – mrz
    Apr 13, 2016 at 8:13
  • $\begingroup$ Thank you for your help. In general the square is not centered in the image. How did you find the "best"? value (second parameter) in EdgeDetect and what is the error of the determined edges? $\endgroup$
    – mrz
    Apr 13, 2016 at 8:34
  • $\begingroup$ @mrz It was determined completely manually. You could probably automatically perform multiple tries and have a some sort of "square goodness of fit" measure to choose results that are probably correct, but at the same time I must say that I'm a bit concerned of the situation if some parts of your image have almost no contrast between the square and the background... $\endgroup$
    – kirma
    Apr 13, 2016 at 9:48
  • $\begingroup$ When it comes to the square not being in the middle, you can use average of corner coordinates instead of ImageDimensions@img/2 to perform sorting by angle on basis of it. $\endgroup$
    – kirma
    Apr 13, 2016 at 9:49
2
$\begingroup$

Fortunately this is not so difficult with Mathematica. First, we detect the straight lines, surrounding square with ImageLines:

img = Import["https://i.stack.imgur.com/QF8Wk.jpg"]; (* get image *)
lines = ImageLines[EdgeDetect[img, 20]][[;; 4]];  (* get lines *)
HighlightImage[img, {Green, Line /@ lines}]  (* show lines *)

enter image description here

First 4 found lines are those we actually need. Then we need coordinates of top left and bottom right corners to crop the image:

topLeft = (RegionIntersection @@ Line /@ lines[[{1, 4}]])[[1, 1]];
bottomRight = (RegionIntersection @@ Line /@ lines[[{2, 3}]])[[1, 1]];
ImageTrim[img, {topLeft, bottomRight}]

enter image description here

That's it!

$\endgroup$
1
  • $\begingroup$ Thank you ... your result is the same as below obtained by kirma. Do you have an idea how one can choose the "best"? most accurate value in EdgeDetect and what is the error of the determined edges? $\endgroup$
    – mrz
    Apr 13, 2016 at 8:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.