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$
  • $\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$ – tsuresuregusa Apr 12 '16 at 13:33
  • $\begingroup$ No ... not by hand ... this is trivial ... $\endgroup$ – mrz Apr 12 '16 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$ – tsuresuregusa Apr 12 '16 at 14:11
3
$\begingroup$

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

Module[{img, poly},
 img = Import["http://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["http://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.

| improve this answer | |
$\endgroup$
  • $\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 '16 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 '16 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 '16 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 '16 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["http://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!

| improve this answer | |
$\endgroup$
  • $\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 '16 at 8:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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