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?
Mathematica Stack Exchange is a question and answer site for users of Wolfram Mathematica. It only takes a minute to sign up.
Sign up to join this communityIn 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}}],
}
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}}]]
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.
EdgeDetect
?
$\endgroup$
ImageDimensions@img/2
to perform sorting by angle on basis of it.
$\endgroup$
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 *)
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}]
That's it!
ImageTake[ Import["http://i.stack.imgur.com/QF8Wk.jpg"], {175, 1300}, {170, 1295}]
or subtract the rings from the square? $\endgroup$