({{, (RefLink[ImageKeypoints, paclet:ref/ImageKeypoints])[image] 
finds key features in image and returns their coordinates.}, {, (RefLink[ImageKeypoints, paclet:ref/ImageKeypoints])[image,prop]
gives the specified property prop for each keypoint.}})

OpenersNotesSection(Spacer1)Details and Options

(RefLink[ImageKeypoints, paclet:ref/ImageKeypoints])[image] finds keypoints in image with image dimensions {w,h} and returns their image coordinates as a list of the form {{(Subscript[x, 1]),(Subscript[y, 1])},{(Subscript[x, 2]),(Subscript[y, 2])},…}.

The following properties can be specified:

(RefLink[ImageKeypoints, paclet:ref/ImageKeypoints]) sorts the results based on the "Strength" property of the keypoints.

(RefLink[ImageKeypoints, paclet:ref/ImageKeypoints])[image,{(Subscript[prop, 1]),(Subscript[prop, 2]),…}] returns multiple properties.

The feature descriptors returned by (RefLink[ImageKeypoints, paclet:ref/ImageKeypoints]) are numerically robust against translation, rotation, and scale changes.

The following options can be specified:

With a setting (RefLink[MaxFeatures, paclet:ref/MaxFeatures])->n, at most n keypoints with largest "Strength" are returned.

Possible method settings include:

When a property is not available with a specified method, the corresponding element in the result is set to (RefLink[Missing, paclet:ref/Missing])["NotAvailable"]. » »

OpenersPrimaryExamplesSection(Spacer1)Examples  (34)

OpenersExampleSection0(Spacer1)Basic Examples  (2)

Find keypoints in an image:

i=;

ImageKeypoints[i]//Short

Highlight keypoints on the image:

HighlightImage[i,%]

Count the number of points of interest in an image:

ImageKeypoints[]//Length

OpenersExampleSection1(Spacer1)Scope  (11)

Keypoints of a grayscale image:

ImageKeypoints[]//Short

Keypoints of a color image:

ImageKeypoints[]//Short

Find keypoints in an image:

ImageKeypoints[]

Return the keypoint descriptor:

ImageKeypoints[,"Descriptor"]

Compute multiple properties:

ImageKeypoints[,{"Scale","Orientation","ContrastSign"}]//MatrixForm

Get properties "Position" and "PixelPosition":

pos=ImageKeypoints[,{"Position","PixelPosition"}]

The two corresponding coordinate systems are offset by half a pixel:

pos[[All,1]]+1/2==pos[[All,2]]

Get the "Scale" in pixels:

img=;

scales=ImageKeypoints[img,"Scale"]

The scale corresponds to the size of an intrinsic region around the keypoint. Visualize the disc region 
around a "SURF" keypoint:

HighlightImage[img,MapThread[Circle,{ImageKeypoints[img,"Position"],2.5*scales}],ImageSize->100]

Get the "Orientation" in radians:

img=;

orient=ImageKeypoints[img,"Orientation"]

Show keypoints with a pattern rotated based on orientation:

HighlightImage[img,
MapThread[
{Circle[#2,5],Line[{#2,#2+5*{Cos[#1],Sin[#1]}}]}&,
{orient,ImageKeypoints[img]}],
ImageSize->200]

Get the "Strength" score:

img=;
strength=ImageKeypoints[img,"Strength"];
strength//Short

Display the distribution of the strength of keypoints in an image:

Histogram@strength

Get the "Descriptor" representing the distribution of pixel values inside a keypoint's neighborhood:

img=;

ImageKeypoints[img,"Descriptor",MaxFeatures->1]

The descriptor is similar to the one of the rotated image:

ImageKeypoints[ImageRotate@img,"Descriptor",MaxFeatures->1]

EuclideanDistance[%,%%]

Get the "OrientedDescriptor" representing the distribution of pixel values inside a keypoint's neighborhood without correcting for the keypoint's orientation:

img=;

ImageKeypoints[img,"OrientedDescriptor",MaxFeatures->1]

The descriptor is different than the descriptor of the same landmark in the rotated image:

ImageKeypoints[ImageRotate@img,"OrientedDescriptor",MaxFeatures->1]

EuclideanDistance[%,%%]

The "ConstrastSign" is 1 for keypoints lighter than their surroundings:

ImageKeypoints[,"ContrastSign"]

The sign is -1 for keypoints darker than their surroundings:

ImageKeypoints[,"ContrastSign"]

OpenersExampleSection2(Spacer1)Options  (9)

OpenersExampleSubsection0(Spacer1)KeypointStrength  (1)

Use a specific threshold for keypoint strength:

ImageKeypoints[,KeypointStrength->.005]

By default, all detected keypoints are returned:

ImageKeypoints[]//Length

OpenersExampleSubsection1(Spacer1)Masking  (1)

By default, all keypoints are returned:

i=;

HighlightImage[i,ImageKeypoints[i]]

Exclude keypoints in the foreground using a mask region:

HighlightImage[i,ImageKeypoints[i,Masking->]]

OpenersExampleSubsection2(Spacer1)MaxFeatures  (1)

By default, all detected keypoints are returned:

img=;

xy=ImageKeypoints[img];
HighlightImage[img,xy]

Get the 50 strongest keypoints:

xy=ImageKeypoints[img,MaxFeatures->50];
HighlightImage[img,xy]

OpenersExampleSubsection3(Spacer1)Method  (6)

By default, "SURF" keypoints are computed:

i=;

HighlightImage[i,ImageKeypoints[i]]

Compute and visualize a different keypoint:

HighlightImage[i,ImageKeypoints[i,Method->"AKAZE",MaxFeatures->80]]

"FAST" and "AGAST" keypoints are defined by their location and strength at scale 3.5:

i=;

ImageKeypoints[i,{"Position","Strength","Scale"},Method->"FAST",MaxFeatures->50]//Short

Compute and visualize FAST keypoints:

HighlightImage[i,ImageKeypoints[i,Method->"FAST",MaxFeatures->50]]

Compute and visualize AGAST keypoints:

HighlightImage[i,ImageKeypoints[i,Method->"AGAST",MaxFeatures->50]]

"BRISK" and "ORB" keypoints are defined by their location, scale, orientation and strength:

img=;

{brisk,orb}=ImageKeypoints[img,{"Position","Scale","Orientation","Strength"},Method->#]&/@{"BRISK","ORB"};

RandomSample[brisk,4]

RandomSample[orb,4]

Descriptors are vectors of 0s and 1s of length 512 for "BRISK" and 256 for "ORB":

{brisk,orb}=ImageKeypoints[img,"Descriptor",Method->#]&/@{"BRISK","ORB"};

brisk[[1]]//Short

orb[[1]]//Short

Dimensions[#]&/@{brisk,orb}

"AKAZE" and "KAZE" keypoints are defined by their location, scale, orientation and strength:

img=;

{akaze,kaze}=ImageKeypoints[img,{"Position","Scale","Orientation","Strength"},Method->#]&/@{"AKAZE","KAZE"};

RandomSample[akaze,4]

RandomSample[kaze,4]

AKAZE descriptors are vectors of 0s and 1s of length 480:

ImageKeypoints[img,"Descriptor",Method->"AKAZE"]//Shallow

Dimensions[%]

KAZE descriptors are vectors of 128 real numbers with unit norm:

ImageKeypoints[img,"Descriptor",Method->"KAZE"]//Short

{Dimensions[%],Norm/@RandomSample[%,5]}

AKAZE oriented descriptors are computed without correcting for keypoints' intrinsic orientation:

img=;

{kod,orientations}=Transpose@ImageKeypoints[img,{"OrientedDescriptor","Orientation"},Method->"AKAZE"];

Oriented descriptors match descriptors for keypoints with orientation close to 0:

δ=MapThread[HammingDistance,{kod,ImageKeypoints[img,"Descriptor",Method->"AKAZE"]}];

Pick[orientations,δ,x_/;x<20]

With the "SURF" method, a keypoint is defined by its location, scale, orientation, contrast sign and strength:

img=;

surf=ImageKeypoints[img,{"Position","Scale","Orientation","ContrastSign","Strength"}];

RandomSample[surf,4]

SURF descriptors consist of vectors of 64 real numbers with unit norm:

ImageKeypoints[img,"Descriptor",Method->"SURF"]//Short

{Dimensions[%],Norm/@RandomSample[%,5]}

Oriented descriptors match descriptors for keypoints with orientation close to 0:

{kod,orientations}=Transpose@ImageKeypoints[img,{"OrientedDescriptor","Orientation"}];

δ=MapThread[EuclideanDistance,{kod,ImageKeypoints[img,"Descriptor"]}];

Pick[orientations,δ,x_/;x<0.15]

OpenersExampleSection3(Spacer1)Applications  (5)

Visualize SURF keypoints using their scale, orientation and contrast:

img=;
points=ImageKeypoints[img,{"Position","Scale","Orientation","ContrastSign"},MaxFeatures->100];
scalefactor=2.5;
HighlightImage[img,Table[{{If[p[[4]]==1,Yellow,Red],Circle[p[[1]],p[[2]]*scalefactor],Line[{p[[1]],p[[1]]+p[[2]]*scalefactor*{Cos[p[[3]]],Sin[p[[3]]]}}]}},{p,points}]]

Visualize BRISK keypoints:

img=;

points=ImageKeypoints[img,{"Position","Scale","Orientation"},Method->"BRISK",MaxFeatures->50];
HighlightImage[img,{FaceForm[],Table[Rotate[{Line[{p[[1]],p[[1]]+p[[2]]*{1,0}}],Rectangle[p[[1]]+p[[2]]*{-1,-1},p[[1]]+p[[2]]*{1,1}]},p[[3]]],{p,points}]}]

Extract local patches of fixed size around detected keypoints:

img=;
ImageTrim[img,{#},12]&/@ImageKeypoints[img,Method->"KAZE",MaxFeatures->100]

Extract patches of size proportional to the scale of keypoints:

{pos,size}=Transpose@ImageKeypoints[img,{"Position","Scale"},Method->"KAZE",MaxFeatures->100];
MapThread[ImageTrim[img,{#1},2*#2]&,{pos,size}]

Use keypoints to crop an image to keep the main features:

imgs={,,};
ImageTrim[#,ImageKeypoints[#,KeypointStrength->.0005],50]&/@imgs

Create thumbnails of uniform size:

ImageCrop[ImageResize[#,{{240},{180}}],{240,180}]&/@%

Object recognition using "bag of words" on a dataset of 5,000 images 32×32 each, belonging to 10 categories:

obj=ResourceObject["CIFAR-10"];
training=ResourceData[obj,"TrainingData"];
testing=Flatten[Table[training[[i+1000;;i+1099]],{i,1,50000,5000}]];training=Flatten[Table[training[[i;;i+499]],{i,1,50000,5000}]];

Compute keypoint descriptors on 256×256 images and create the codebook of visual words:

AbsoluteTiming[
kp=ParallelTable[
ImageKeypoints[ImageResize[i,256],"Descriptor"],{i,training[[All,1]]}
];]

The codebook contains all image descriptors of length 64:

codebook=Flatten[kp,1];
Dimensions[codebook]

Find 100 visual codewords using k-means clustering:

AbsoluteTiming[
clust=ClusteringComponents[codebook,100,1,Method->"KMeans",PerformanceGoal->"Speed"];]

codewords=Table[
p=Flatten@Position[clust,i];
Mean[codebook[[p]]],
{i,Max@clust}];

Image features are defined as the normalized counts of all the codewords:

nf=Nearest[codewords->Automatic];

imageCodewordsFeatureExtract[image_?ImageQ]:=imageCodewordsFeatureExtract[ImageKeypoints[ImageResize[image,{256,256}],"Descriptor"]];
imageCodewordsFeatureExtract[keypoints_List]:=Module[
{h},
h=N@BinCounts[First@nf[#,1] &/@keypoints, {1,Length@codewords+1}];
h/Total[h]
];

imageCodewordsFeatureExtract[RandomSample[training][[1,1]]]//Histogram

Construct a classifier trained on extracted image features:

t=Table[imageCodewordsFeatureExtract[kp[[i]]]->training[[i,2]],
{i,Length@training}];

classifier=Classify[t];

Evaluate the classifier on test data:

cm=ClassifierMeasurements[classifier,Table[imageCodewordsFeatureExtract[First@sample]->Last@sample,{sample,testing}]];

cm["ConfusionMatrixPlot"]

OpenersExampleSection4(Spacer1)Properties & Relations  (7)

Not all properties are supported for all methods:

({{, "Contrast\nSign", "Descriptor", "Orientation", "Oriented\nDescriptor", "Pixel\nPosition", "Position", "Scale", "Strength"}, {"AGAST", "–", "–", "–", "–", "✓", "✓", "✓", "✓"}, {"AKAZE", "–", "✓", "✓", "✓", "✓", "✓", "✓", "✓"}, {"BRISK", "–", "✓", "✓", "–", "✓", "✓", "✓", "✓"}, {"FAST", "–", "–", "–", "–", "✓", "✓", "✓", "✓"}, {"KAZE", "–", "✓", "✓", "✓", "✓", "✓", "✓", "✓"}, {"ORB", "–", "✓", "✓", "–", "✓", "✓", "✓", "✓"}, {"SURF", "✓", "✓", "✓", "✓", "✓", "✓", "✓", "✓"}})

(RefLink[Missing, paclet:ref/Missing])["NotAvailable"] is returned when a property is not available with the specified method:

ImageKeypoints[,{"Position","Descriptor"},Method->"FAST",MaxFeatures->5]

"FAST" method does not find contrast sign:

ImageKeypoints[,{"Position","ContrastSign"},Method->"AGAST",MaxFeatures->4]

"BRISK" method does not compute oriented descriptors:

ImageKeypoints[,{"Position","OrientedDescriptor"},Method->"BRISK",MaxFeatures->4]

"SURF" and "KAZE" descriptors are typically compared using the Euclidean distance:

img=;

kp=ImageKeypoints[img,{"Position","Descriptor"},MaxFeatures->11,Method->"KAZE"];

Distances between the strongest keypoint and each of the next 10 strongest:

best=kp[[1,2]];
distances=Table[EuclideanDistance[best,d],{d,kp[[2;;,2]]}]

"AKAZE", "BRISK" and "ORB" descriptors are typically compared using the Hamming distance:

kp=ImageKeypoints[img,{"Position","Descriptor"},MaxFeatures->11,Method->"BRISK"];

Distances between the strongest keypoint and each of the next 10 strongest:

best=kp[[1,2]];
distances=Table[HammingDistance[best,d],{d,kp[[2;;,2]]}]

Cluster the keypoints based on their descriptors:

img=;
k=ImageKeypoints[img,{"Position","Descriptor"},MaxFeatures->80];
clust=FindClusters[k[[All,2]]->k[[All,1]], 3];
colors=ColorData[3]/@Range[Length[clust]];
HighlightImage[img,Transpose[{colors,clust}]]

(RefLink[ImageCorners, paclet:ref/ImageCorners]) may be used as keypoints:

img=;

Computer corners using radius 3.5 for similarity to the scale of some keypoint detectors:

corners=ImageCorners[img,3.5,MaxFeatureDisplacement->1,MaxFeatures->10]

HighlightImage[img,{White,corners}]

Use (RefLink[CornerFilter, paclet:ref/CornerFilter]) to get the strength of detected corners:

cf=CornerFilter[img,3.5];
strengths=ImageValue[cf,corners];
Transpose[{corners,strengths}]

Top 10 FAST keypoints:

ImageKeypoints[img,{"Position","Strength"},Method->"FAST",MaxFeatures->10]

Top 10 AGAST keypoints:

ImageKeypoints[img,{"Position","Strength"},Method->"AGAST",MaxFeatures->10]

(RefLink[ImageCorrespondingPoints, paclet:ref/ImageCorrespondingPoints]) gives the locations for keypoints that have matching descriptors:

{img1,img2}={,};

{pos1,pos2}=ImageCorrespondingPoints[img1,img2];

MapThread[HighlightImage,{{img1,img2},{pos1,pos2}}]

Compute keypoints on both images:

{k1,k2}=ImageKeypoints[#,{"Position","Descriptor"},MaxFeatures->100]&/@{img1,img2};

Take two keypoints with and without a corresponding point in the second image:

{m,n}={k1[[37]],k1[[1]]};

Compute all distances between descriptors for these keypoint to all keypoints in the second image:

δm=EuclideanDistance[m[[2]],#]&/@k2[[All,2]];
δn=EuclideanDistance[n[[2]],#]&/@k2[[All,2]];

Histogram[#,ImageSize->200]&/@{δm,δn}

The second-to-nearest ratio is typically used to decide whether a keypoint has a corresponding point:

{bestm,secondbestm}=TakeSmallestBy[k2,EuclideanDistance[m[[2]],#[[2]]]&,2];
{bestn,secondbestn}=TakeSmallestBy[k2,EuclideanDistance[n[[2]],#[[2]]]&,2];

EuclideanDistance[m[[2]],secondbestm[[2]]]/EuclideanDistance[m[[2]],bestm[[2]]]

EuclideanDistance[n[[2]],secondbestn[[2]]]/EuclideanDistance[n[[2]],bestn[[2]]]

The keypoint with a correspondence is red; the other one is yellow:

{HighlightImage[img1,{Red,m[[1]],Yellow,n[[1]]},ImageSize->250],
HighlightImage[img2,{White,k2[[All,1]],Yellow,bestn[[1]],Red,bestm[[1]]},ImageSize->250]}

({{DocumentationFooterIconsRelatedFunction.png, ({{See Also}, {(RefLink[ImageCorrespondingPoints, paclet:ref/ImageCorrespondingPoints])  ▪  (RefLink[CornerFilter, paclet:ref/CornerFilter])  ▪  (RefLink[ImageCorners, paclet:ref/ImageCorners])  ▪  (RefLink[ImageSaliencyFilter, paclet:ref/ImageSaliencyFilter])  ▪  (RefLink[ImageAlign, paclet:ref/ImageAlign])}})}})

({{DocumentationFooterIconsRelatedGuide.png, ({{Related Guides}, {▪(RefLinkPlain[Feature Detection, paclet:guide/FeatureDetection])}, {▪(RefLinkPlain[Image Processing & Analysis, paclet:guide/ImageProcessing])}, {▪(RefLinkPlain[Computer Vision, paclet:guide/ComputerVision])}, {▪(RefLinkPlain[Image Computation for Microscopy, paclet:guide/ImageComputationForMicroscopy])}})}})