How many animals can one find in a random image?

Posted 3 years ago
28374 Views
|
5 Replies
|
23 Total Likes
|
 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] 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] 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] 393These are the shapes positioned in the original image. Show[HighlightMesh[#,Style[2, RandomColor[]]]&/@ shapes] 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}] 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"}] Here are some more animal-shapes found in other random images. 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]]]  getOptimalAnimal[shapes[[27]]] 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]]] Using different method options for ImageMesh gives different results. Here are some animal-shaped regions from a 300*300 image and method "MarchingSquares". Attachments:
Answer
5 Replies
Sort By:
Posted 3 years ago
 - Congratulations! This post is now Staff Pick! Thank you for your wonderful contributions. Please, keep them coming!
Answer
Posted 3 years 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:
Answer
Posted 3 years 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.
Answer
Posted 3 years 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!
Answer
Posted 3 years ago
 I think this paper has some relevance: Seeing shapes in seemingly random spatial patterns: Fractal analysis of Rorschach inkblotsTaylor 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
Answer
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments