Message Boards Message Boards

How many animals can one find in a random image?

GROUPS:
wolfram science image processing recreation visual arts geometry graphics and visualization wolfram language machine learning staff picks

The long evolutionary history of humans has optimized the recognition of animals in the human vision system. To escape predators and to find food. Sometimes we believe to see animals and human faces, even if there aren't any, this phenomena is called pareidolia, or more generally apophenia. Classic examples are Jesus on a toast (Liu2014), the image on the shroud of Turin (Sheen2016), Elvis in a potato chip (Voss2011), and the face on Mars (Martinez-Conde2012). In many cases, in about 100ms (Naber2012) humans can identify animal shapes. Some animals, e.g. snakes are potentially identified much faster (VanLe2013).

So, an interesting question might be: how often do we (believe to) see animals in an genuinely random image?

Here is, in the literal sense of the word, a random image of size 300*300 pixels:

SeedRandom[4056380]; 
dim=300;
randomImage = Image[Table[RandomChoice[{2,1}->{0,1}],{dim},{dim}]];
Show[randomImage,ImageSize -> 300]

enter image description here

No animal shapes are directly visible.

Using ImageMesh we can get the individual/connected components (some potentially animal-like shaped) as regions (this operation is not fully deterministic, so results below may vary).

Show[imesh=ImageMesh[randomImage,Method->"DualMarchingSquares"],ImageSize -> 300]

enter image description here

These are the individual shapes. We ignore too small and too large regions. For our image we find neatly 400 regions.

(* this takes a minute *)
shapes=Select[ConnectedMeshComponents@imesh,18< Area[#]<2000&];
Length[shapes]

393

These are the shapes positioned in the original image.

Show[HighlightMesh[#,Style[2, RandomColor[]]]&/@ shapes]

enter image description here

For later use, we define one function to make a random image and get the shapes.

getShapes[{black_,white_}, dim_] :=Select[ConnectedMeshComponents@
ImageMesh[Image[Table[RandomChoice[{black,white}->{0,1}],{dim},{dim}]],
Method->"DualMarchingSquares"],18< Area[#]<2000&]

As we want to interpret the shapes as animals, we smooth the edges. We switch from regions to graphics.

smooth[reg_] :=Graphics[{Lighter[Blue], 
(ToExpression[ToString[InputForm@reg],StandardForm,Hold] /.
HoldPattern[BoundaryMeshRegion[v_,b__,___Rule]]:>GraphicsComplex[v,FilledCurve[{b}/.
Line[l_]:> BSplineCurve[DeleteDuplicates[Flatten[l,1]],
SplineClosed->True,SplineDegree->2]]])[[1]]}]

We also allow changing the orientation and color.

rotate[g_,α_] := With[{m={{Cos[α],Sin[α]},{-Sin[α], Cos[α]}}},g/.
GraphicsComplex[v_, r__]:> GraphicsComplex[m.#&/@ v,r]]

flip[g_] := g/.GraphicsComplex[v_, r__]:> GraphicsComplex[{-1,1}#&/@ v,r]

recolor[g_,col_] := g/.c_RGBColor:>col

animalize[g_,{f_,α_,col_}] := Graphics[ recolor[rotate[If[f, flip,Identity]@
smooth[g],α],col], PlotRange -> All]&[smooth[g]]

Here are some of the shapes that were hiding in the above image.The human eye tries to see fishes, wales, birds, squirrels, frogs, ducks, sea-horses, bunnies, deers, dogs, cats and similar creatures as well as human heads.

GraphicsGrid[Partition[Show[#, ImageSize -> 120,Frame->True,FrameTicks->False]&/@#,5]&@
{ animalize[shapes[[18]],{False,1.8,GrayLevel[0.1]}],
  animalize[shapes[[99]],{False,1.1,Darker[Yellow]}], 
  animalize[shapes[[6]],{False,0.7,Darker[Blue]}],
  animalize[shapes[[14]],{False,0.,Darker[Brown]}],
  animalize[shapes[[4]],{False,0.5,Darker[Red]}],
  animalize[shapes[[23]],{False,0,Darker[Orange]}],
  animalize[shapes[[76]],{False,0,Darker[Orange,0.6]}],
  animalize[shapes[[95]],{False,-1.5,Darker[Green,0.4]}], 
  animalize[shapes[[9]],{False,0.,Brown}],
  animalize[shapes[[163]],{False,1.1,Darker[Purple]}]},
Spacings->{5,-20}]

enter image description here

Looking at the last selection shows the importance of one or two eyes in the shapes (Yang2015). Eyes are often used by nature for deception (Steven2014).

A small Manipulate will allow to optimize the animal-perception by changing color, orientation, and aspect ratio.

makeManipulate[shape_]:=Manipulate[Graphics[ recolor[rotate[If[f, flip,Identity]@ #[[1]],α],col],
ImageSize -> 120,AspectRatio->ar,PlotRange -> All],
OpenerView[{"modify",Column[{
Control[{{α,0,"rotate"},-Pi,Pi,ImageSize->Small}],
Control[{{f,False,"reflect"},{True,False},ImageSize->Small}],
Control[{{col, Darker[Blue],"color"},Red,ImageSize->Tiny}],
Control[{{ar, Automatic,"aspect ratio"},0.2,5,ImageSize->Small}]}]}],
SaveDefinitions->True,TrackedSymbols:>True]&[smooth[#]]&@ shape

Manipulate[makeManipulate[shapes[[j]]],{{j,141,""},1, Length[shapes],1,Appearance->"Labeled"}]

enter image description here

Here are some more animal-shapes found in other random images.

enter image description here

One could now try to automate the finding of animals using ImageIdentify. In general, the interpretation of ImageIdentify will depend on the image orientation. So, we maximize over different orientations.

getOptimalAnimal[shape_] := 
Module[{s=smooth[shape][[1]],tab,ras,tab2},
tab=Table[{(ras=Rasterize[Graphics[rotate[s,\[Alpha]],ImageSize -> 120,PlotRange -> All]]),
      Normal@KeyDrop[ImageIdentify[ras,"animal",2,"Probability"],Entity["Concept",#]&/@
 {"Person::93r37","Hominid::tt93h","Mammal::nt5bz",
"SeaStar::46w97","Shark::632s8","CanisFamiliaris::597qc"}]},
{\[Alpha], 0, 2Pi, 2Pi/24}]; 
tab2=Sort[{#2[[1,2]], #2[[1,1]], #1}&@@@DeleteCases[ tab,{_,{}}]];
{tab2[[-1,3]]->tab2[[-1,2]],"Probabilty" -> tab2[[-1,1]]}]

As ImageIdentify was trained on real photographs, it is not the ideal tool for this task. It is biased towards humans, mammals, and sharks.

getOptimalAnimal[shapes[[10]]]

enter image description here

getOptimalAnimal[shapes[[27]]]

enter image description here

To answer the original question: in a random 400x400 pixel image, one easily finds a few dozen animals. Here are four dozen animal-shape like smoothed regions from random 400x400 image.

Module[{gs, gs2},
 SeedRandom[2222];
 gs = getShapes[{2, 1}, 400];
 gs2 = {animalize[gs[[3]], {False, 0, GrayLevel[0.1]}], 
   animalize[gs[[6]], {False, 1, GrayLevel[0.1]}], 
   animalize[gs[[9]], {False, 1.3, GrayLevel[0.1]}], 
   animalize[gs[[15]], {False, -1, GrayLevel[0.1]}], 
   animalize[gs[[17]], {False, 0.3, GrayLevel[0.1]}], 
   animalize[gs[[30]], {True, 2.3, GrayLevel[0.1]}], 
   animalize[gs[[39]], {False, 0.3, GrayLevel[0.1]}], 
   animalize[gs[[40]], {True, -0.1, GrayLevel[0.1]}], 
   animalize[gs[[48]], {False, -0.1, GrayLevel[0.1]}], 
   animalize[gs[[53]], {True, -0.1, GrayLevel[0.1]}], 
   animalize[gs[[55]], {True, -0.1, GrayLevel[0.1]}], 
   animalize[gs[[62]], {True, 2.3, GrayLevel[0.1]}], 
   animalize[gs[[64]], {False, 0, GrayLevel[0.1]}], 
   animalize[gs[[65]], {False, 0, GrayLevel[0.1]}], 
   animalize[gs[[68]], {False, -0.2, GrayLevel[0.1]}], 
   animalize[gs[[73]], {True, -0.3, GrayLevel[0.1]}], 
   animalize[gs[[81]], {False, 0.2, GrayLevel[0.1]}], 
   animalize[gs[[86]], {True, 3.4, GrayLevel[0.1]}], 
   animalize[gs[[97]], {False, 0.3, GrayLevel[0.1]}], 
   animalize[gs[[100]], {False, 0.9, GrayLevel[0.1]}], 
   animalize[gs[[101]], {False, 2.6, GrayLevel[0.1]}], 
   animalize[gs[[115]], {False, 4.3, GrayLevel[0.1]}], 
   animalize[gs[[124]], {False, 0, GrayLevel[0.1]}], 
   animalize[gs[[125]], {False, 2.9, GrayLevel[0.1]}], 
   animalize[gs[[139]], {False, 0, GrayLevel[0.1]}], 
   animalize[gs[[146]], {False, -1.6, GrayLevel[0.1]}], 
   animalize[gs[[175]], {False, -1., GrayLevel[0.1]}], 
   animalize[gs[[201]], {True, -0.5, GrayLevel[0.1]}], 
   animalize[gs[[209]], {True, 3.1, GrayLevel[0.1]}], 
   animalize[gs[[210]], {False, -1.4, GrayLevel[0.1]}], 
   animalize[gs[[218]], {True, 3.2, GrayLevel[0.1]}], 
   animalize[gs[[227]], {True, -0.3, GrayLevel[0.1]}], 
   animalize[gs[[229]], {True, 0.9, GrayLevel[0.1]}], 
   animalize[gs[[253]], {True, 0., GrayLevel[0.1]}], 
   animalize[gs[[273]], {True, -0.3, GrayLevel[0.1]}], 
   animalize[gs[[278]], {True, 1., GrayLevel[0.1]}], 
   animalize[gs[[282]], {True, 3, GrayLevel[0.1]}], 
   animalize[gs[[298]], {False, 0, GrayLevel[0.1]}], 
   animalize[gs[[299]], {False, 0.6, GrayLevel[0.1]}], 
   animalize[gs[[318]], {False, 2., GrayLevel[0.1]}], 
   animalize[gs[[326]], {False, 3, GrayLevel[0.1]}], 
   animalize[gs[[340]], {False, -1.3, GrayLevel[0.1]}], 
   animalize[gs[[352]], {True, -13, GrayLevel[0.1]}], 
   animalize[gs[[361]], {True, -13, GrayLevel[0.1]}], 
   animalize[gs[[365]], {False, 2.4, GrayLevel[0.1]}], 
   animalize[gs[[377]], {True, 2.6, GrayLevel[0.1]}], 
   animalize[gs[[395]], {False, 0.3, GrayLevel[0.1]}], 
   animalize[gs[[405]], {True, 0.3, GrayLevel[0.1]}]};
 Grid[Partition[Framed[Show[#, ImageSize -> 100]] & /@ 
    SortBy[gs2, FullOptions[#, AspectRatio] &], 6]]]

enter image description here

Using different method options for ImageMesh gives different results. Here are some animal-shaped regions from a 300*300 image and method "MarchingSquares".

enter image description here

Attachments:
POSTED BY: Michael Trott
Answer
2 months ago

enter image description here - Congratulations! This post is now Staff Pick! Thank you for your wonderful contributions. Please, keep them coming!

POSTED BY: Moderation Team
Answer
2 months ago

This is absolutely marvelous! I did see quite a few nicely "recognizable" shapes. That is the same story of seeing shapes in the clouds or constellations in stars. But what it really reminds me of is shadowgraphy or ombromanie:

enter image description here

POSTED BY: Marina Shchitova
Answer
2 months ago

They are similar to the symbols from Pre-Columbian cultures like the Incas, Mayans and Aztecs. Maybe this code could moonlight as a hieroglyph translator.

enter image description here

POSTED BY: Billy Shore
Answer
2 months ago

So it's true! Weird creatures are everywhere.... Even in random images :) If 1 random image can already create so easily these beautiful shapes it really makes you wonder about how wired we are to see stuff that's not there. Or is it? The shapes are there observed by an algorithm that observes a bit like us. It's again all about context. Can't wait to start playing with your posted notebook!

POSTED BY: l van Veen
Answer
2 months ago

I think this paper has some relevance:

Seeing shapes in seemingly random spatial patterns: Fractal analysis of Rorschach inkblots

Taylor RP, Martin TP, Montgomery RD, Smith JH, Micolich AP, Boydston C, et al. (2017)

PLoS ONE 12(2): e0171289. doi:10.1371/journal.pone.0171289

with popular account given in Nature: Fractal secrets of Rorschach's famed ink blots revealed

POSTED BY: Vitaliy Kaurov
Answer
1 month ago

Group Abstract Group Abstract