We're getting into the "If I go down I'm takin' youse guys wit' me" phase of the mob boss saga.
https://www.yahoo.com/news/politics/articles/trump-newsmax-impeached-again-lots-001337140.html
1000 results for “three_star_dave”
We're getting into the "If I go down I'm takin' youse guys wit' me" phase of the mob boss saga.
https://www.yahoo.com/news/politics/articles/trump-newsmax-impeached-again-lots-001337140.html
Three bold predictions for the Nets’ 2026-2027 NBA season: One star will be dealt away https://www.rawchili.com/nba/861331/ #Basketball #BrooklynNets #JordiFernandez #JuliusRandle #MichaelPorterJr #NBA #NbaPreview #NewOrleans #NewOrleansPelicans #NewOrleans #NewOrleansPelicans #Pelicans #SeanMarks #Sports #SportsPlus
Everton star Merlin Rohl stopped in street by three word shout from Scousers
https://www.liverpoolecho.co.uk/news/liverpool-news/everton-star-merlin-rohl-stopped-34778864
The Everton star spoke to the ECHO in an exclusive interview about how he has settled in the city, his love for Lark Lane and his new photobook #EFC #Toffees #EvertonFC #LarkLane #Aigburth
Tyrese Haliburton drops ruthless three-word insult on Milwaukee Bucks star in OT defeat https://www.rawchili.com/nba/862242/ #Basketball #Indiana #IndianaPacers #IndianaPacers #MilwaukeeBucks #NBA #Pacers #RyanRollins #TyreseHaliburton
Mississauga’s Pitch Pine Crescent: Three mysterious deaths
Host Amy Dempsey Raven, an investigative reporter for the Toronto Star, spent more than a decade asking…
#NewsBeep #News #Mississauga #CA #Canada #mississauga
https://www.newsbeep.com/ca/938286/
Mississauga’s Pitch Pine Crescent: Three mysterious deaths
Host Amy Dempsey Raven, an investigative reporter for the Toronto Star, spent more than a decade asking…
#Canada #Mississauga
https://www.europesays.com/canada/255134/
Barcelona player ratings vs Real Betis: Lamine Yamal shines as five-star Catalans dismantle Manuel Pellegrini’s side
Joan Garcia – 6/10 Had a relatively quiet afternoon in terms of shot-stopping volume, making three saves. While…
#Spain #ES #Europe #Europa #EU #Barcelona #H.Flick #L.Yamal #LaLiga #Playerratings #RealBetis #RealBetisvsBarcelona
https://www.europesays.com/spain/102018/
Barcelona player ratings vs Real Betis: Lamine Yamal shines as five-star Catalans dismantle Manuel Pellegrini’s side
Joan Garcia – 6/10 Had a relatively quiet afternoon in terms of shot-stopping volume, making three saves. While…
#Spain #ES #Europe #Europa #EU #Barcelona #H.Flick #L.Yamal #LaLiga #Playerratings #RealBetis #RealBetisvsBarcelona
https://www.europesays.com/spain/102006/
https://www.europesays.com/africa/477274/ KRA seizes 52 refurbished phones and three drones at JKIA #53PHONES #cleaner #JKIA #Kenya #KenyaNews #KRA #passenger #seized #star #StarNews #StarNewsKenya #StarNewspaper #StarNewspaperKenya #TheStar #TheStarKenya #TheStarNewspaper #ThreeDrones
The Rams have managed to transform themselves from a superteam to a midteam
By Alex Kirshner
Los Angeles were tipped as a Super Bowl contender after assembling a star studded lineup. Now they’ve lost three of their last four games
https://www.theguardian.com/sport/2026/oct/19/los-angeles-rams-superteam-struggles-nfl-football
#LosAngelesRams #NFL #USsports #ArizonaCardinals #Sport #WestCoast #TheGuardian #AlexKirshner
Davies ensures Spurs off the bottom after first win of season against Coventry
By Jacob Steinberg at the Tottenham Hotspur Stadium
Tottenham are level with Beyoncé at last. Progress is represented in Roberto De Zerbi’s side earning only their sixth home win in the Premier League since November 2024. Cynics will point out that this spectacular stadium has hosted as many of the American pop star’s gigs during that time, but Spurs are finally singing a happier tune after dragging themselves out of the bottom three thanks to a messy but gritty 3-1 win over Coventry.
https://www.theguardian.com/football/2026/oct/19/tottenham-coventry-premier-league-match-report
#PremierLeague #TottenhamHotspur #CoventryCity #Football #Sport #TheGuardian #JacobSteinbergattheTottenhamHotspurStadium
Some news from Spain, part CLXXVI !!!
This is yours truly with another episode of some news from Spain !!! Lots of things going on This is Spain, let me tell you my latest news chosen by yours truly, By the way CLXXV is old Roman numeral for 176, Therefore, here is my take on some news from Spain, part CLXXVI !!! Hope you enjoy this post as I.
Hidden among vineyards and stately streets in La Rioja lies a town that is home to one of the most unique monasteries in Spain, one inaugurated by Pope Adrian VI in the 16C. Its history is also marked by a mysterious legend involving Juana la Loca or Joanna the Mad. This place is Casalarreina, a town in La Rioja Alta located just a few kms from Haro, which houses the Monastery of Nuestra Señora de la Piedad, the only monastery in Spain to have been inaugurated by a pope. Its origins date back to the 16C, when Juan Fernández de Velasco, Bishop of Calahorra and La Calzada, obtained authorization from Pope Julius II in 1509 to build the convent. Construction began in 1514, but the event that truly distinguished this monument occurred in 1522, when Pope Adrian VI visited during his journey to Rome and presided over the monastery’s inauguration. Its primary attraction is the spectacular Plateresque-style portal, designed like an elaborate stone altarpiece and adorned with religious sculptures, botanical motifs, and intricate reliefs. The monastery blends the elegance of the late Gothic period with early Renaissance elements, while the interior features a striking two-story cloister, star-vaulted ceilings, and 16C Plateresque choir stalls. For those traveling by car, the town is conveniently served by the AP-68 highway/motorway, which provides quick connections to Bilbao, Burgos, Madrid, Logroño, Zaragoza, and Barcelona. Additionally, the N-124 highway runs through the area, and the N-232 is also nearby. These routes offer fast access to several other nearby towns of great tourist interest, such as Haro, Briones ,and San Vicente de la Sonsierra. Also the LR-111, which connects to Haro, Santo Domingo de la Calzada, and Ezcaray, and the N-120, which runs parallel to the Camino de Santiago. The official Casalarreina on the monastery : https://www.casalarreina.es/lugar-de-interes/monasterio-de-nuestra-senora-de-la-piedad/
The Castilla-La Mancha region hides one of the most striking geological landscapes in Spain. In the province of Guadalajara, a UNESCO-recognized geopark brings together impressive canyons, lagoons, waterfalls, and rock formations that offer a glimpse into millions of years of Earth’s history. This is the Molina-Alto Tajo Geopark, spans over 4,200 square kilometers approximately one-third of the province of Guadalajara encompasses more than 70 villages/towns. Over millennia, the Tagus river, with its characteristic emerald-green waters, has carved out deep canyons and gorges. Notable sites include the canyons of the Tagus and Gallo rivers, the Mesa Valley, the high plateaus of Maranchón and Aragoncillo, the Taravilla lagoon,Honda and La Salobreja lagoons, and waterfalls such as the Salto de Poveda and La Escaleruela. Also featured are the unique rock formations of Chequilla and Peñalén, which showcase the region’s extraordinary geological diversity. Within its boundaries lie the Alto Tajo Natural Park and the Sierra de Caldereros Natural Monument, along with various other protected areas. The Castilla La Mancha region tourist office on the Molina-Alto Tajo Geopark : https://www.turismocastillalamancha.es/es/naturaleza/monumentos-naturales/geoparque-de-la-comarca-de-molina-alto-tajo
At no, 96 Calle de Alcalá formerly no, 102, on the corner of Calle de Narváez and next to Plaza Felipe II, stands the building where Federico García Lorca lived until July 1936. Many memorials this year marking the 90 anniversary of his assassination, See my post about him in my blog,
The Museo Sorolla Museum has expanded into a former car workshop in the heart of the Chamberí neighborhood, at 68 Calle Zurbano. Designed as a continuation of the historic property, this expansion provides the museum with temporary exhibition halls and an auditorium, as well as additional areas and facilities for the handling, storage, and management of its collections. The result is a complex comprising two buildings, one dating from the early 20C and the other from the early 21C, that together form the present-day Sorolla Museum.(see post)
Tracing the path of Goya: from Fuendetodos to Madrid, via Zaragoza. We find ourselves in the Campo de Belchite ,province of Zaragoza, in the very same humble house built of adobe, wood, and stone, with tiny bedrooms where Goya was born on March 30, 1746. It was from here that he would have traveled back and forth to the Church of the Assumption in Plaza de las Reliquias, where the genius painted one of his earliest works on wooden doors. Nearby lies the Engraving Museum at 3 Calle Zuloaga, established following an auction of works by various painters, organized to bring prints by the Aragonese master to his hometown. Goya’s printed work engravings he initially began as a pastime to master the techniques of Velázquez is now regarded as a kind of intimate diary. In Zaragoza, 50 km from Fuendetodos, one is struck by the vastness of the blue sky which turns pink at sunset arching over the Goya Museum, which reopens this past Friday, October 9 2026. A few meters away, in the Basilica of the Pilar,(see post) the master’s personality is strikingly evident in every brushstroke of his two great frescoes works that also reveal a contrast between two distinct periods of his life. In 1772, having just returned from his apprenticeship in Italy, he created *The Adoration of the Name of God*. Nine years later, he painted *Regina Martyrum* in a style characterized by brushwork intended to be viewed from a distance, a technique not well understood at the time. Madrid itself serves as a museum dedicated to Goya to his life and work, his contradictions and his convictions. Key sites include (see posts) ,the Royal Tapestry Factory, where he once worked; the Basilica of San Francisco el Grande, featuring a dome painted by the master; the Royal Academy of San Fernando which he eventually directed, despite an initial rejection where more than ten of his works are housed; the Prado Museum; the Lázaro Galdiano Museum; and the Hermitage of San Antonio de la Florida. (see posts), Together, these locations allow the traveler to explore the shifting perspectives and evolution of Goya’s vision, and it is here, too, that the genius lies buried. Of the estate and house where he lived during his final period in Madrid are known as the Quinta del Sordo or Villa of the Deaf Man before departing for exile in Bordeaux in 1824, almost nothing remains, save for an inscription noting that it was here he created his *Black Paintings*. Having lived through war, endured illness, and retreated into the silence of deafness, Goya was a changed man. Following the *Trienio Liberal* (the three-year liberal period), Ferdinand VII imposed authoritarian rule, restored absolutism, and brought in French troops. Goya sought refuge in Bordeaux among intellectual friends. In 1827, a year before his death, he painted *The Milkmaid of Bordeaux*; the young woman, seated on a mule and carrying a jug of milk, appears beneath an immense sky tinged with the same shades of blue he knew in his childhood. Today, the painting can be seen at the Prado Museum.
A sanctuary for Hollywood stars on the Gran Vía, (see post) letters from Christopher Columbus at the Liria Palace, (see post) and a lost portrait of George Washington at the San Fernando Royal Academy of Fine Arts are all part of a tour through 12 locations in the city that commemorates the 250th anniversary of the independence of the United States. If there was one Madrid phone number that Frank Sinatra knew by heart, it was that of Museo Chicote, (see post) the legendary cocktail bar on the Gran Vía where Hollywood royalty drank during the 1950s. Among them was Ava Gardner; the singer of “My Way”, and her husband at the time would call in the early hours of the morning to find out where his famous wife was. A staff member at what Luis Buñuel dubbed the “Sistine Chapel of martinis” would pass the message along to the actress and, if necessary, help hide a lover. This establishment also housed the first American-style bar in Europe. Another record-breaking venue, Botín, the oldest restaurant in the world is also featured on the route; it was frequented by figures such as Charlton Heston, Jacqueline Kennedy, Woody Allen, and Bruce Springsteen. It also served as an inspiration for Ernest Hemingway, who mentioned it in his novel *The Sun Also Rises* , and always sat at the same table on the second floor. George Washington is another key figure featured in the 60,000 maps illustrated by artist Ana Rojo that will be distributed at hotels and tourist spots throughout the city, and which will also be available online. This is because the San Fernando Royal Academy of Fine Arts houses one of the few existing portraits of the first U.S. president located outside of his home country. The portrait was painted by the Italian artist Josef Perovani in 1796, commissioned by the Spanish ambassador in Philadelphia as a gift for Mariano Godoy, Secretary of State to King Charles IV. Washington also appears in an enamel miniature by the London-born artist William Russell Birch, a master of the technique which is on display at the Lázaro Galdiano Museum.(see post), Next, we head to the Liria Palace, (see post) built around the same time as the American Revolution. It houses an important collection of letters by Christopher Columbus, as well as various coats of arms granted to explorers and newly founded cities in the New World ; fundamental documents for understanding the history of the Americas and the cultural impact across continents. The collection also includes a previously unknown portrait of Philip III, attributed to Diego Velázquez, which had been lost for centuries until it was discovered by Nashville-based historian and philanthropist William B. Jordan, who donated it to the Prado Museum in 2016. Meanwhile, the Naval Museum (see post) holds the 1500 *Carta Universal* by Juan de la Cosa, the first world map to feature a depiction of the Americas. The Geominero Museum (IGME-CSIC) showcases remarkable fossils and minerals discovered on U.S. soil, including a replica of the skull of “Stan” the *Tyrannosaurus rex* from South Dakota, and beetle specimens preserved in tar from the Rancho La Brea site in California. We then move on to the Royal Botanical Garden, (see post), which is home to Carolina allspice, American persimmons, and orange trees associated with the Osage Nation of Oklahoma, among many other trees and plants native to the United States. We also visit one of the most intriguing sites on our route: the 19C *Beti Jai* frontón, a Basque pelota court. One of the oldest of its kind in Europe, the building served as a factory for Studebaker vehicles and a Harley-Davidson dealership after it ceased hosting Basque pelota matches in 1919. Our final stops are the Casa de la Moneda or Royal Mint (see post), which has released a commemorative series highlighting the Spanish contribution to American independence,and the International Institute, established in 1892 by Boston-born educator Alice Gordon Gulick, it was modeled after women’s colleges on the East Coast. Between 1944 and 1950, it also served as the site of the U.S. Embassy.
From Aranjuez to Chinchón by bike: two historic towns connected by pedal power on the first stage of the Gran Tour de Madrid. This is the opening leg of the CiclaMadrid “Gran Tour”, a 432 km circular route divided into 17 sections that allow cyclists to explore the four major regions of the Comunidad de Madrid region, that is Sierra Norte, Sierra de Guadarrama, Sierra Oeste, and the Las Vegas/Alcarria area. We depart from Aranjuez (see posts), along the right bank of the Tagus river, cycling until we reach a turnoff toward Villaconejos. Along this stretch, it is well worth visiting the striking charca rosa or pink pond known as Laguna Seca or Dry Lagoon, which remains waterless for most of the year. You can also visit the Melon Museum ;the only one of its kind in the world, and the Cueva del Fraile or Friar’s Cave, a 300-year-old cellar carved into a small hill; inside, there are nineteen alcoves where friars of the Discalced Carmelite Order once stored their large wine jars. Leaving Villaconejos, we take the path next to the Hermitage of Santa Ana to begin the ascent toward Chinchón.(see posts) A visit to its world-famous Plaza Mayor is a must; it is considered one of the most beautiful squares in the world and, in 2008, was named the “Fourth Wonder of the Community of Madrid.” After all, who could forget Cantinflas (famous Mexican actor/comedian) practicing his bullfighting passes there in the film Around the World in 80 Days, After the effort of cycling this first leg of the “Grand Tour”, and, while we’re at it, try to recall some of the many other films shot here. These include Orson Welles’s The Immortal Story, which through the magic of cinema transformed Chinchón into Macao; Circus World, which brought John Wayne and Rita Hayworth to a Plaza Mayor reimagined as the American West; and, more recently, Wes Anderson’s Asteroid City. It’s a cinematic conclusion to an engaging and leisurely bike ride between two of Madrid’s region historic towns. The official ClicaMadrid Gran Tour : https://cyclemadrid.com/fr/gran-tour-ciclamadrid/
There you go folks, another dandy tour of my dear Spain. It is time to enjoy my some news from Spain once again, Remember,Spain is everything under the Sun ! A very special post, always remember where it all begin, it is you ! Again, hope you enjoy the post on some news from Spain, part CLXXVI !!! as I.
And remember ,happy travels, good health, and many cheers to all !!!
Rate this:
#Madrid #SpainComputer Vision with .NET
A deep-dive walkthrough of integrating computer vision into .NET applications — covering image classification (ML.NET and ONNX Runtime), object detection with YOLO-style models, OCR (Azure AI Vision, Document Intelligence, Tesseract), face and object recognition and the legal and ethical constraints around them, image embeddings and visual search, Azure AI Vision, OpenCV integration with OpenCvSharp, image processing APIs (ImageSharp, SkiaSharp and others), multimodal LLMs versus classical vision, and building a production vision service in ASP.NET Core.
Table of Contents
Introduction
Computer vision is the field of getting software to understand images and video: what is in a photo, where each object is, what a document says, whether two pictures show the same thing. For .NET developers it has become practical in two ways at once: managed cloud services (Azure AI Vision and Document Intelligence) turn many tasks into a single API call, and the ONNX ecosystem lets you run state-of-the-art open models inside your own process, on your own hardware, with no Python in production.
Image / video frame
↓
Decode + preprocess (ImageSharp / SkiaSharp / OpenCV: resize, normalize, orient)
↓
Model (cloud API | ONNX Runtime | ML.NET | multimodal LLM)
↓
Postprocess (softmax, boxes + non-max suppression, text assembly, thresholds)
↓
Business logic (store, search, flag for review, trigger a workflow)
This is the pipeline behind every technique in this guide. Most vision bugs hide in the first and third stages — preprocessing that doesn't match what the model was trained on, and postprocessing that misreads the model's output — not in the model itself. The guide's emphasis follows: how to wire each task correctly, how to choose between a managed API, a self-hosted model, and a multimodal LLM, and how to measure whether the result is good enough.
A note on versions and services. Cloud vision services evolve and retire features (older Computer Vision API versions, Custom Vision, and some Face capabilities have been retired or restricted over time), SDK package names and signatures change between releases, and model output formats differ across model versions. Treat the samples here as illustrating the shape of each integration, compile them against the package versions you install, and check current service documentation for availability, regions, limits, and lifecycle status before committing to a design.
1. The Computer Vision Landscape in .NET
The tasks
CLASSIFICATION What is in this image? "cat", "defective", "invoice" one label (or a few) per image
OBJECT DETECTION What objects are where? boxes + labels + confidence "3 cars at these coordinates"
SEGMENTATION Which pixels belong to which object? per-pixel masks medical imaging, background removal
OCR What text is in this image? text + positions receipts, IDs, signs, scanned PDFs
DOCUMENT ANALYSIS Structure and fields of a document tables, key-value pairs invoices, forms
FACE TASKS Detect, verify, identify faces boxes, embeddings, match scores (heavily regulated — Section 5)
EMBEDDINGS A vector capturing the image's meaning float[ ] visual search, dedupe, recommendations
CAPTIONING / VQA Describe or answer questions about image natural language accessibility, search, assistants
The four ways to get a vision capability
1. MANAGED CLOUD API Azure AI Vision (Image Analysis, Read OCR), Azure AI Document Intelligence, Azure AI Face.
+ No ML expertise, fast to build, maintained and improved for you.
- Per-call cost, data leaves your boundary (unless containers), limited customization,
vendor features change and retire.
2. PRE-TRAINED MODEL ON Download an ONNX model (ResNet, MobileNet, YOLO, CLIP, ArcFace...) and run it in-process
ONNX RUNTIME with Microsoft.ML.OnnxRuntime.
+ Full control, no per-call fee, data stays local, runs offline/at the edge, can use GPU.
- You own preprocessing/postprocessing, model hosting, performance, and licensing checks.
3. TRAIN YOUR OWN Fine-tune a model on your labeled images — ML.NET transfer learning for classification, or
train in PyTorch/TensorFlow/Azure ML and export to ONNX.
+ Best accuracy on your specific domain (defect types, your products).
- Needs labeled data, evaluation discipline, and MLOps.
4. MULTIMODAL LLM Send the image to a vision-capable chat model (see Section 10).
+ Extremely flexible, zero-shot, handles messy real-world images and open-ended questions.
- Cost, latency, non-determinism, hallucination risk, weaker at precise localization and
counting, and data-privacy considerations.
The core .NET packages
Microsoft.ML.OnnxRuntime (+ .Gpu / .DirectML) Run ONNX models in-process (CPU, CUDA, DirectML)
Microsoft.ML + Microsoft.ML.Vision + Microsoft.ML.ImageAnalytics ML.NET image classification via transfer learning
SixLabors.ImageSharp (+ .Drawing) Managed, cross-platform image processing
SkiaSharp Fast 2D graphics and image processing (Skia)
OpenCvSharp4 (+ runtime packages) OpenCV bindings: classic CV, video, DNN
Azure.AI.Vision.ImageAnalysis Azure AI Vision Image Analysis 4.0 (captions, tags, objects, read OCR, people)
Azure.AI.DocumentIntelligence Document OCR, layout, and prebuilt/custom extractors
Tesseract Open-source OCR engine wrapper
Microsoft.Extensions.AI Vision-capable chat models via IChatClient (Section 10)
System.Numerics.Tensors Vector math (cosine similarity) for embeddings
A decision shortcut
"Read the text/fields from documents" -> Azure AI Document Intelligence (or Vision Read for plain OCR)
"Describe / tag / caption general photos" -> Azure AI Vision Image Analysis, or a multimodal LLM
"Detect common objects (people, cars, ...)" -> Azure AI Vision Objects/People, or a YOLO ONNX model
"Classify MY specific categories (defects, SKUs)" -> ML.NET transfer learning or a fine-tuned model exported to ONNX
"Find similar images / search images by text" -> image embeddings (CLIP-style) + vector search
"Identify people by face" -> stop and read Section 5 first (legal, ethical, and access constraints)
"Process / resize / crop / draw on images" -> ImageSharp, SkiaSharp, or OpenCvSharp
2. Image Classification
Assign a label (or probabilities over labels) to a whole image
Classification answers "what is this a picture of?" The output is a probability for each known class; you take the top one (or top-k) and apply a confidence threshold. This series' AI/ML Fundamentals guide covers the underlying concepts (training vs. inference, overfitting, precision/recall) that apply here unchanged.
Option A: Run a pre-trained model with ONNX Runtime
Models trained on large general datasets (such as ImageNet's 1,000 classes) are available in ONNX format. Running one means loading the model, preprocessing the image exactly as the model expects, running inference, and decoding the output.
// dotnet add package Microsoft.ML.OnnxRuntime
// dotnet add package SixLabors.ImageSharp
using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
public sealed class ImageClassifier : IDisposable
{
private readonly InferenceSession _session; // create ONCE and reuse — loading a model is expensive
private readonly string _inputName;
private readonly string[] _labels;
// ImageNet normalization used by many torchvision-trained models — MUST match YOUR model's training
private static readonly float[] Mean = [0.485f, 0.456f, 0.406f];
private static readonly float[] Std = [0.229f, 0.224f, 0.225f];
public ImageClassifier(string modelPath, string labelsPath)
{
_session = new InferenceSession(modelPath);
_inputName = _session.InputMetadata.Keys.First();
_labels = File.ReadAllLines(labelsPath);
}
public IReadOnlyList<(string Label, float Probability)> Classify(Image<Rgb24> image, int topK = 3)
{
// 1. PREPROCESS: resize + center-crop to 224x224, scale to 0..1, normalize, order as NCHW (batch, channel, height, width)
using var resized = image.Clone(x => x.Resize(new ResizeOptions { Size = new Size(224, 224), Mode = ResizeMode.Crop }));
var tensor = new DenseTensor<float>([1, 3, 224, 224]);
resized.ProcessPixelRows(accessor =>
{
for (int y = 0; y < accessor.Height; y++)
{
Span<Rgb24> row = accessor.GetRowSpan(y);
for (int x = 0; x < row.Length; x++)
{
tensor[0, 0, y, x] = (row[x].R / 255f - Mean[0]) / Std[0];
tensor[0, 1, y, x] = (row[x].G / 255f - Mean[1]) / Std[1];
tensor[0, 2, y, x] = (row[x].B / 255f - Mean[2]) / Std[2];
}
}
});
// 2. INFERENCE
using var results = _session.Run([NamedOnnxValue.CreateFromTensor(_inputName, tensor)]);
float[] logits = results.First().AsEnumerable<float>().ToArray();
// 3. POSTPROCESS: softmax turns raw scores (logits) into probabilities that sum to 1
float max = logits.Max();
float[] exp = logits.Select(l => MathF.Exp(l - max)).ToArray(); // subtract max for numerical stability
float sum = exp.Sum();
return exp.Select((e, i) => (Label: _labels[i], Probability: e / sum))
.OrderByDescending(x => x.Probability)
.Take(topK)
.ToList();
}
public void Dispose() => _session.Dispose();
}
THE PREPROCESSING MUST MATCH TRAINING. Check your model's documentation for:
- INPUT SIZE (224x224, 256x256, 384x384 ...)
- CHANNEL ORDER RGB vs BGR (OpenCV loads BGR; most deep-learning models expect RGB)
- LAYOUT NCHW (batch, channels, height, width) vs NHWC
- SCALING 0..1 vs 0..255 vs -1..1
- NORMALIZATION per-channel mean/std (or none)
- RESIZE POLICY stretch vs. preserve aspect ratio with crop or padding
A mismatch doesn't throw an error — it just silently degrades accuracy. This is the #1 cause of "the model works in Python
but gives garbage in .NET."
Option B: Train your own classifier with ML.NET (transfer learning)
For your categories — product types, defect vs. OK, plant diseases — ML.NET can fine-tune the top of a pre-trained network on your labeled images. This is transfer learning: the pre-trained network already knows general visual features, so you need far less data (often hundreds of images per class rather than millions).
// dotnet add package Microsoft.ML
// dotnet add package Microsoft.ML.Vision
// dotnet add package Microsoft.ML.ImageAnalytics
// dotnet add package SciSharp.TensorFlow.Redist (the TensorFlow runtime ML.NET's vision trainer uses)
using Microsoft.ML;
using Microsoft.ML.Vision;
public class ImageData
{
public string ImagePath { get; set; } = "";
public string Label { get; set; } = ""; // e.g. the name of the folder the image sits in
}
public class ImagePrediction
{
public string PredictedLabel { get; set; } = "";
public float[] Score { get; set; } = [];
}
var mlContext = new MLContext(seed: 1);
// Folder layout: images/<label>/<file>.jpg — one subfolder per class
IEnumerable<ImageData> images = Directory.EnumerateFiles("images", "*.jpg", SearchOption.AllDirectories)
.Select(path => new ImageData { ImagePath = path, Label = Directory.GetParent(path)!.Name });
IDataView data = mlContext.Data.ShuffleRows(mlContext.Data.LoadFromEnumerable(images));
// Convert the string label to a numeric "key" and load the raw image bytes
var preprocess = mlContext.Transforms.Conversion.MapValueToKey("LabelAsKey", nameof(ImageData.Label))
.Append(mlContext.Transforms.LoadRawImageBytes("Image", null, nameof(ImageData.ImagePath)));
IDataView processed = preprocess.Fit(data).Transform(data);
var split = mlContext.Data.TrainTestSplit(processed, testFraction: 0.3, seed: 1);
var validation = mlContext.Data.TrainTestSplit(split.TestSet, testFraction: 0.5, seed: 1);
IDataView trainSet = split.TrainSet, validationSet = validation.TrainSet, testSet = validation.TestSet;
var options = new ImageClassificationTrainer.Options
{
FeatureColumnName = "Image",
LabelColumnName = "LabelAsKey",
ValidationSet = validationSet,
Arch = ImageClassificationTrainer.Architecture.ResnetV2101, // the pre-trained network to build on
MetricsCallback = Console.WriteLine, // progress and validation accuracy per epoch
TestOnTrainSet = false,
ReuseTrainSetBottleneckCachedValues = true, // cache the expensive feature extraction between epochs
ReuseValidationSetBottleneckCachedValues = true,
};
var pipeline = mlContext.MulticlassClassification.Trainers.ImageClassification(options)
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel"));
ITransformer model = pipeline.Fit(trainSet);
// Evaluate on images the model never trained on (see AI/ML Fundamentals, Section 8)
var predictions = model.Transform(testSet);
var metrics = mlContext.MulticlassClassification.Evaluate(predictions, labelColumnName: "LabelAsKey", predictedLabelColumnName: "PredictedLabel");
Console.WriteLine($"Micro-accuracy: {metrics.MicroAccuracy:P1} Macro-accuracy: {metrics.MacroAccuracy:P1}");
mlContext.Model.Save(model, trainSet.Schema, "imageClassifier.zip");
(This follows the pattern of ML.NET's image-classification tutorials; the trainer's architecture options and required runtime packages change over time, so check the current ML.NET documentation. For deeper modeling or newer architectures, a common route is to train in PyTorch and export to ONNX, then run with ONNX Runtime as in Option A.)
Option C: Managed tagging
Azure AI Vision's Image Analysis returns general tags and captions for a photo with no training at all (Section 7) — a fine fit when "is there a dog in it?" level labeling suffices and your categories are common ones.
Classification practicalities
CONFIDENCE THRESHOLDS A classifier always returns SOME label, even for an image unlike anything it has seen. Apply a threshold
and add an "unknown / needs human review" path — don't act on a 41% prediction as if it were certain.
CLASS IMBALANCE If 95% of images are "OK," accuracy is misleading (see AI/ML Fundamentals, Section 9). Track precision, recall,
and per-class results, and use a confusion matrix.
DATA QUALITY OVER MODEL Consistent labels and images representative of PRODUCTION conditions (lighting, angle, camera, backgrounds) matter
more than the architecture. Models trained on clean studio photos fail on blurry phone snapshots.
SPLIT BY SOURCE Near-duplicate images (frames of the same video, photos of the same object) must stay on one side of the
train/test split, or you'll measure memorization.
AUGMENTATION Flips, crops, brightness/contrast changes, and small rotations expand your data and improve robustness.
MULTI-LABEL If an image can have several labels at once, you need a multi-label setup (independent probabilities), not softmax.
3. Object Detection
Find objects and their locations
Classification says what; object detection says what and where: a list of bounding boxes, each with a label and a confidence score. It powers counting, safety monitoring, inventory, cropping, and any workflow that needs to act on a specific region.
Output of a detector for one image:
[ { label: "person", confidence: 0.91, box: (x=120, y=64, w=88, h=210) },
{ label: "car", confidence: 0.84, box: (x=410, y=190, w=260, h=130) }, ... ]
Running a YOLO-style model with ONNX Runtime
YOLO-family models are the most common real-time detectors, and exported ONNX versions run well from .NET. The wiring has three parts that must all be right: letterbox preprocessing, inference, and postprocessing (decode boxes, filter by confidence, and apply non-maximum suppression).
using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using RectangleF = System.Drawing.RectangleF; // avoid ambiguity with ImageSharp's own RectangleF
public record Detection(string Label, float Confidence, RectangleF Box);
public sealed class ObjectDetector : IDisposable
{
private const int InputSize = 640;
private readonly InferenceSession _session;
private readonly string _inputName;
private readonly string[] _labels;
public ObjectDetector(string modelPath, string[] labels)
{
_session = new InferenceSession(modelPath);
_inputName = _session.InputMetadata.Keys.First();
_labels = labels;
}
public IReadOnlyList<Detection> Detect(Image<Rgb24> original, float confThreshold = 0.25f, float iouThreshold = 0.45f)
{
// 1. LETTERBOX: scale to fit 640x640 while PRESERVING aspect ratio, padding the rest with gray
float scale = Math.Min((float)InputSize / original.Width, (float)InputSize / original.Height);
int newW = (int)(original.Width * scale), newH = (int)(original.Height * scale);
int padX = (InputSize - newW) / 2, padY = (InputSize - newH) / 2;
using var resized = original.Clone(x => x.Resize(newW, newH));
var input = new DenseTensor<float>([1, 3, InputSize, InputSize]);
input.Fill(114f / 255f); // padding color
resized.ProcessPixelRows(accessor =>
{
for (int y = 0; y < accessor.Height; y++)
{
Span<Rgb24> row = accessor.GetRowSpan(y);
for (int x = 0; x < row.Length; x++)
{
input[0, 0, y + padY, x + padX] = row[x].R / 255f; // YOLO-style models typically want RGB scaled 0..1
input[0, 1, y + padY, x + padX] = row[x].G / 255f;
input[0, 2, y + padY, x + padX] = row[x].B / 255f;
}
}
});
// 2. INFERENCE
using var results = _session.Run([NamedOnnxValue.CreateFromTensor(_inputName, input)]);
Tensor<float> output = results.First().AsTensor<float>(); // YOLOv8-style layout: [1, 4 + numClasses, numAnchors]
int numClasses = output.Dimensions[1] - 4;
int numAnchors = output.Dimensions[2];
// 3. POSTPROCESS: decode candidate boxes
var candidates = new List<Detection>();
for (int i = 0; i < numAnchors; i++)
{
int bestClass = 0; float bestScore = 0;
for (int c = 0; c < numClasses; c++)
{
float score = output[0, 4 + c, i];
if (score > bestScore) { bestScore = score; bestClass = c; }
}
if (bestScore < confThreshold) continue;
float cx = output[0, 0, i], cy = output[0, 1, i], w = output[0, 2, i], h = output[0, 3, i];
// Undo the letterbox: model coordinates -> original image coordinates
float x1 = (cx - w / 2 - padX) / scale;
float y1 = (cy - h / 2 - padY) / scale;
candidates.Add(new Detection(_labels[bestClass], bestScore, new RectangleF(x1, y1, w / scale, h / scale)));
}
// 4. NON-MAXIMUM SUPPRESSION: remove duplicate overlapping boxes for the same object
return NonMaxSuppression(candidates, iouThreshold);
}
private static List<Detection> NonMaxSuppression(List<Detection> detections, float iouThreshold)
{
var kept = new List<Detection>();
foreach (var group in detections.GroupBy(d => d.Label)) // per-class NMS
{
var remaining = group.OrderByDescending(d => d.Confidence).ToList();
while (remaining.Count > 0)
{
Detection best = remaining[0];
kept.Add(best);
remaining.RemoveAt(0);
remaining.RemoveAll(d => IoU(best.Box, d.Box) > iouThreshold);
}
}
return kept;
}
private static float IoU(RectangleF a, RectangleF b)
{
RectangleF inter = RectangleF.Intersect(a, b);
float interArea = inter.IsEmpty ? 0 : inter.Width * inter.Height;
float union = a.Width * a.Height + b.Width * b.Height - interArea;
return union <= 0 ? 0 : interArea / union;
}
public void Dispose() => _session.Dispose();
}
The concepts behind that code
BOUNDING BOX A rectangle: (x, y, width, height) or (x1, y1, x2, y2). Models may output center-based (cx, cy, w, h) —
convert carefully.
CONFIDENCE The model's score for the detection; filter by a threshold. Lower = more detections and more false
positives; higher = fewer false positives but more misses.
IoU "Intersection over Union": the overlap between two boxes divided by their combined area (0 = no overlap,
1 = identical). Used both for NMS and for evaluating detections against ground truth.
NMS Detectors emit many overlapping boxes per object. NMS keeps the most confident box and discards others
that overlap it above the IoU threshold.
LETTERBOXING Preserving aspect ratio (padding) instead of stretching — stretched images distort object shapes and hurt
accuracy, and you MUST map boxes back to the original image's coordinates afterward.
Model-specific details to verify
OUTPUT LAYOUT Differs by model family and export settings: some outputs include a separate "objectness" score, some are transposed
([1, numAnchors, 4 + classes]), and some exports bake NMS into the model. Inspect the output shape
(session.OutputMetadata) and the model's documentation — the code above matches the YOLOv8-style layout.
LABELS The class-name list must match the model's training (80 COCO classes for common pretrained checkpoints).
LICENSE Check the license of the model and its weights before commercial use — some popular detectors use licenses with
obligations (such as copyleft terms) that matter for products.
PERFORMANCE Indexing a Tensor per element is convenient but slow; for throughput, copy to a float[] and index with arithmetic.
Use GPU execution providers (CUDA, DirectML) and smaller or quantized (INT8) models where latency matters.
Managed and trainable alternatives
AZURE AI VISION The Image Analysis API returns detected objects, people, and tags with bounding boxes — no model to host,
good for common categories (Section 7).
CUSTOM DETECTORS For YOUR objects (a specific part, a defect type), fine-tune a detector on labeled images (label with a tool like
CVAT or Label Studio), train in PyTorch or Azure ML, export to ONNX, and run with the code above.
ML.NET Offers object detection via Model Builder and Azure-based training workflows; check current documentation for
what it supports.
Using detections
COUNTING Count boxes per class — but beware occlusion, tiny objects, and duplicates; validate counts against ground truth.
CROPPING Crop each box and send it to a second model (a classifier, OCR, or a face model) — a common multi-stage pipeline.
REGION RULES "Alert when a person is inside this polygon" — geometry on top of detections.
TRACKING (VIDEO) Detection works per frame. To follow an object across frames you need a tracking layer (e.g. SORT/ByteTrack-style
algorithms) that associates detections over time.
THRESHOLDS PER CLASS Tune confidence per class — a safety-critical class may deserve a lower threshold (accepting false alarms)
than a convenience feature.
4. OCR
Turning pixels of text into text
Optical Character Recognition extracts text from images — scanned documents, photos of receipts and signs, screenshots, ID cards. Modern OCR returns not just the text but structure: lines and words with bounding boxes, reading order, and often tables and fields.
The OCR options
AZURE AI VISION READ Cloud OCR for printed and handwritten text in photos and documents, many languages. Part of the
Image Analysis 4.0 API. Good for general "get me the text" needs.
AZURE AI DOCUMENT Document-focused: layout (paragraphs, tables, selection marks), prebuilt models (invoices, receipts,
INTELLIGENCE IDs, business cards, tax forms) that return structured FIELDS, and custom models trained on your
forms. The right tool for documents rather than photos.
TESSERACT Open-source engine, runs locally. Free and offline, but accuracy depends heavily on image quality and
preprocessing; weaker on photos, handwriting, and complex layouts.
OTHER LOCAL ENGINES PaddleOCR (via .NET wrappers) and platform OCR (such as Windows' built-in OCR) are options with
different accuracy, language, and portability trade-offs.
MULTIMODAL LLMs Vision-capable chat models can read text and extract structured fields from messy images
(Section 10) — flexible, but slower and costlier, and they can hallucinate text.
Azure AI Vision: Read
// dotnet add package Azure.AI.Vision.ImageAnalysis
using Azure;
using Azure.AI.Vision.ImageAnalysis;
var client = new ImageAnalysisClient(new Uri(endpoint), new AzureKeyCredential(key)); // or an Entra ID TokenCredential
ImageAnalysisResult result = await client.AnalyzeAsync(
BinaryData.FromBytes(imageBytes), // or pass a Uri to an image the service can fetch
VisualFeatures.Read);
foreach (DetectedTextBlock block in result.Read.Blocks)
foreach (DetectedTextLine line in block.Lines)
{
Console.WriteLine(line.Text);
foreach (DetectedTextWord word in line.Words)
Console.WriteLine($" {word.Text} (confidence {word.Confidence:P0})");
}
Azure AI Document Intelligence: layout and prebuilt fields
// dotnet add package Azure.AI.DocumentIntelligence
using Azure;
using Azure.AI.DocumentIntelligence;
var docClient = new DocumentIntelligenceClient(new Uri(endpoint), new AzureKeyCredential(key));
// "prebuilt-layout" returns text, tables, and structure; "prebuilt-invoice", "prebuilt-receipt", "prebuilt-idDocument"... return typed fields
Operation<AnalyzeResult> operation = await docClient.AnalyzeDocumentAsync(
WaitUntil.Completed, "prebuilt-invoice", BinaryData.FromBytes(pdfOrImageBytes));
AnalyzeResult analysis = operation.Value;
foreach (AnalyzedDocument doc in analysis.Documents)
{
if (doc.Fields.TryGetValue("VendorName", out DocumentField? vendor))
Console.WriteLine($"Vendor: {vendor.ValueString} (confidence {vendor.Confidence:P0})");
if (doc.Fields.TryGetValue("InvoiceTotal", out DocumentField? total))
Console.WriteLine($"Total: {total.ValueCurrency?.Amount}");
}
(SDK method shapes for Document Intelligence have changed between releases; check the version you install.) Prebuilt models save enormous effort on common document types: instead of OCR-then-regex, you get named, typed fields with per-field confidence scores — the key to deciding which extractions need human review.
Tesseract: local OCR
// dotnet add package Tesseract (also download the trained-data files, e.g. eng.traineddata, into ./tessdata)
using Tesseract;
using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var pix = Pix.LoadFromFile("scan.png");
using var page = engine.Process(pix);
Console.WriteLine(page.GetText());
Console.WriteLine($"Mean confidence: {page.GetMeanConfidence():P0}");
OCR quality depends on the image — preprocess
RESOLUTION Aim for roughly 300 DPI equivalent for documents; upscale tiny text before OCR.
CONTRAST Convert to grayscale and apply adaptive thresholding (binarization) to separate text from uneven backgrounds.
DESKEW Rotate skewed scans so lines are horizontal. Correct orientation (EXIF rotation, upside-down pages).
DENOISE Remove speckle and scanner noise; avoid blurring text itself.
CROP Remove borders, shadows, and non-text regions.
LIGHTING Phone photos often have shadows and glare — normalize illumination.
// Typical OpenCvSharp cleanup before OCR (Section 8)
using OpenCvSharp;
using var src = Cv2.ImRead("receipt.jpg", ImreadModes.Color);
using var gray = new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
using var denoised = new Mat();
Cv2.GaussianBlur(gray, denoised, new Size(3, 3), 0);
using var binary = new Mat();
Cv2.AdaptiveThreshold(denoised, binary, 255, AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, blockSize: 31, c: 15);
Cv2.ImWrite("receipt-clean.png", binary);
Cloud services such as Read and Document Intelligence do much of this internally and are usually more forgiving than Tesseract; for local OCR, preprocessing is the difference between mediocre and good results.
Working with OCR output
CONFIDENCE Use word/line/field confidence to route low-confidence results to human review rather than trusting them blindly.
VALIDATE Cross-check extracted values: totals equal the sum of line items; dates parse; account numbers pass checksums;
VAT numbers match a pattern. Validation catches OCR errors that confidence scores miss.
STRUCTURE For tables and forms use a layout-aware service rather than reconstructing columns from raw text.
LANGUAGES / SCRIPTS Verify support for your languages and scripts, including right-to-left text and handwriting.
RAG PIPELINES OCR is the first stage of ingesting scanned PDFs for retrieval (see this series' RAG guide, Section 3): detect low-text PDF
pages and route them through OCR.
SENSITIVE DATA IDs, medical forms, and financial documents are sensitive. Control where images are sent, how long they're retained, and who
can see the extracted text (see the security notes in Section 11).
Measuring OCR
Evaluate with character error rate (CER) and word error rate (WER) — the edit distance between OCR output and the ground-truth text, divided by the reference length — plus field-level accuracy for structured extraction:
static double CharacterErrorRate(string reference, string hypothesis)
{
if (reference.Length == 0) return hypothesis.Length == 0 ? 0 : 1;
return (double)Levenshtein(reference, hypothesis) / reference.Length;
}
static int Levenshtein(string a, string b)
{
var previous = Enumerable.Range(0, b.Length + 1).ToArray();
for (int i = 1; i <= a.Length; i++)
{
var current = new int[b.Length + 1];
current[0] = i;
for (int j = 1; j <= b.Length; j++)
current[j] = Math.Min(Math.Min(current[j - 1] + 1, previous[j] + 1), previous[j - 1] + (a[i - 1] == b[j - 1] ? 0 : 1));
previous = current;
}
return previous[b.Length];
}
5. Face and Object Recognition
Be precise about what "face recognition" means
FACE DETECTION "Is there a face, and where?" — boxes (and optionally landmarks such as eyes and nose). The least sensitive
task; used for auto-cropping, blurring, camera focus, and counting.
FACE VERIFICATION "Are these two images the same person?" (1:1). Used for unlocking a device or matching a selfie to an ID photo.
FACE IDENTIFICATION "Who is this, among a set of known people?" (1:N). Searches a gallery of enrolled faces. The most sensitive task.
FACE ATTRIBUTES Inferring age, gender, emotion, or other traits from a face. Scientifically contested and discontinued or
restricted by major providers (below). Avoid.
Treat face recognition as a legal and ethical decision first
Faces are biometric data. Using them to identify people carries obligations and, in some jurisdictions and contexts, prohibitions. This is not a footnote:
LAW AND REGULATION Biometric identification is treated as sensitive or special-category data under laws such as the GDPR, and some
jurisdictions have dedicated biometric statutes (for example Illinois' BIPA, with consent, retention, and
private-right-of-action provisions). The EU AI Act restricts or prohibits certain biometric uses — for example
real-time remote biometric identification in public spaces by law enforcement (with narrow exceptions), untargeted
scraping of facial images to build databases, and emotion recognition in workplaces and schools. Rules differ by
country and are evolving: consult legal counsel before building anything that identifies people by face.
CONSENT AND PURPOSE Obtain informed consent where required, use faces only for the stated purpose, and don't repurpose them.
DATA PROTECTION Store face embeddings/templates as sensitive data: encryption, strict access control, minimal retention,
deletion on request, and a clear policy for what happens when a person withdraws consent.
BIAS AND ACCURACY Face recognition accuracy has been shown to vary across demographic groups and imaging conditions. A system that
works well on average can fail badly — and unfairly — on specific groups. Evaluate by subgroup, set conservative
thresholds, and never make high-stakes decisions on a face match alone.
PLATFORM POLICIES Microsoft's Azure Face service applies a Limited Access policy: identification and verification features require an
approved application and use case, and the earlier capabilities for inferring attributes like emotion, gender, and age
were retired. Other vendors have their own restrictions. Read the current terms.
ALTERNATIVES Often a less invasive design meets the need: a badge or PIN plus a face DETECTION step for privacy blurring, 1:1
verification against a document the user provides, or on-device matching where templates never leave the user's device.
The technical pipeline (for lawful, consented uses)
1. DETECT Find faces in the image (a face detector returns boxes and landmarks).
2. ALIGN Crop and rotate so eyes and mouth sit in standard positions — recognition models expect aligned faces.
3. EMBED A face-recognition network (ArcFace/FaceNet-style, available as ONNX models) converts each aligned face to a vector
(commonly 128-512 numbers) such that the same person's photos land close together.
4. COMPARE Verification: cosine similarity (or distance) between two embeddings vs. a threshold.
Identification: nearest-neighbor search over a gallery of enrolled embeddings (vector search — see this series'
Embeddings & Vector Search guide), then apply the threshold to the best match.
5. DECIDE A threshold trades false accepts against false rejects (below). Add liveness detection to defeat photos and replays.
// Verification with embeddings from a face-recognition ONNX model (embedding extraction code is analogous to the classifier above)
float[] a = faceEmbedder.Embed(alignedFaceA);
float[] b = faceEmbedder.Embed(alignedFaceB);
float similarity = TensorPrimitives.CosineSimilarity(a, b);
bool samePerson = similarity >= threshold; // choose the threshold from a labeled validation set, NOT from a blog post
FALSE ACCEPT RATE (FAR) Different people judged to be the same — the SECURITY failure.
FALSE REJECT RATE (FRR) The same person judged different — the USABILITY failure.
The threshold trades one for the other. Pick it on a labeled validation set representative of your users and conditions, to meet a
target FAR for your risk level, and re-measure by subgroup.
LIVENESS / ANTI-SPOOFING Without it, a printed photo or a screen replay can fool recognition. Use liveness checks for any
authentication use.
Face detection in .NET (the low-risk task)
// Classic detector via OpenCvSharp — simple and dependency-light, but less accurate than modern deep-learning detectors
using OpenCvSharp;
using var cascade = new CascadeClassifier("haarcascade_frontalface_default.xml");
using var image = Cv2.ImRead("group.jpg");
using var gray = new Mat();
Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY);
Rect[] faces = cascade.DetectMultiScale(gray, scaleFactor: 1.1, minNeighbors: 5, flags: HaarDetectionTypes.ScaleImage, minSize: new Size(40, 40));
foreach (Rect face in faces)
Cv2.Rectangle(image, face, Scalar.Red, 2); // or: blur the region to anonymize people in an image
Modern deep-learning face detectors (such as the YuNet model supported by OpenCV's DNN module, or ONNX-exported detectors) are considerably more accurate than Haar cascades, especially for non-frontal and small faces; Azure AI Vision's people/face detection and the Azure Face service are managed options for detection.
"Object recognition": specific things, not just categories
CATEGORY RECOGNITION "That is a laptop" — classification/detection (Sections 2-3).
INSTANCE RECOGNITION "That is THIS exact product (SKU 4471)" or "this is a photo of the Eiffel Tower" — distinguishing specific instances.
The modern approach is EMBEDDING-BASED: embed a reference image of each known item, embed the query image, and
find the nearest reference via vector search (Section 6). Adding a new product means adding an embedding — no retraining.
6. Image Embeddings
A vector that captures what an image means
An image embedding is a list of numbers (often hundreds to a thousand-plus) produced by a vision model such that visually or semantically similar images get nearby vectors — the same idea as text embeddings (see this series' Embeddings & Vector Search guide), applied to pixels. With embeddings you can compare, search, and cluster images without labeling anything.
Multimodal embeddings: images and text in one space
Models in the CLIP family are trained on image–text pairs so that an image and its description land close together in the same vector space. That unlocks cross-modal search: embed a text query ("red running shoes on a trail") and find the nearest images.
IMAGE → vector image embedding model
TEXT → vector text embedding model (the PAIRED model of the SAME family)
Compare with cosine similarity: text-to-image search, image-to-image search, zero-shot classification.
Where embeddings come from
AZURE AI VISION MULTIMODAL EMBEDDINGS A managed API that embeds images AND text into a shared space (REST endpoints for vectorizing images and text).
No model to host.
CLIP-STYLE MODELS VIA ONNX Open CLIP-family models exported to ONNX run locally with ONNX Runtime — an image encoder and a text
encoder (the text side needs the matching tokenizer, which is the fiddly part).
VISION BACKBONES Features from image models such as ResNet or DINO-style networks work well for image-to-image similarity
(not text search) — export the model so its feature (pre-classification) layer is exposed.
MULTIMODAL LLM PROVIDERS Some providers offer multimodal embedding endpoints; check availability.
A small abstraction
public interface IImageEmbedder
{
Task<float[]> EmbedImageAsync(byte[] imageBytes, CancellationToken ct = default);
Task<float[]> EmbedTextAsync(string text, CancellationToken ct = default); // only meaningful for multimodal (CLIP-style) models
}
A managed implementation is a thin HTTP call (the exact URL, API version, and request shape for Azure AI Vision's multimodal embeddings should be taken from the current documentation):
public sealed class AzureVisionEmbedder(HttpClient http, string endpoint, string key) : IImageEmbedder
{
// Illustrative: confirm the route, api-version, and model-version in the current Azure AI Vision documentation
public async Task<float[]> EmbedImageAsync(byte[] imageBytes, CancellationToken ct = default)
{
using var request = new HttpRequestMessage(HttpMethod.Post,
$"{endpoint}/computervision/retrieval:vectorizeImage?api-version=2024-02-01&model-version=2023-04-15")
{
Content = new ByteArrayContent(imageBytes) { Headers = { ContentType = new("application/octet-stream") } }
};
request.Headers.Add("Ocp-Apim-Subscription-Key", key);
using var response = await http.SendAsync(request, ct);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadFromJsonAsync<EmbeddingResponse>(cancellationToken: ct);
return json!.Vector;
}
public async Task<float[]> EmbedTextAsync(string text, CancellationToken ct = default) { /* the vectorizeText counterpart */ throw new NotImplementedException(); }
private record EmbeddingResponse(float[] Vector);
}
What you can build
// 1. INDEX: embed every catalog image once and store the vector (with the image id and metadata) in a vector store
foreach (var product in catalog)
await store.UpsertAsync(product.Id, await embedder.EmbedImageAsync(product.ImageBytes), product.Metadata);
// 2. SEARCH BY IMAGE: "find products that look like this photo"
float[] queryVector = await embedder.EmbedImageAsync(uploadedPhotoBytes);
var similar = await store.SearchAsync(queryVector, top: 10, filter: tenantFilter);
// 3. SEARCH BY TEXT (multimodal models only): "red leather handbag"
float[] textVector = await embedder.EmbedTextAsync("red leather handbag");
var matches = await store.SearchAsync(textVector, top: 10, filter: tenantFilter);
// 4. ZERO-SHOT CLASSIFICATION: compare the image to text prompts for each candidate label — no training data
string[] labels = ["cat", "dog", "bird"];
var labelVectors = await Task.WhenAll(labels.Select(l => embedder.EmbedTextAsync($"a photo of a {l}")));
float[] imageVector = await embedder.EmbedImageAsync(imageBytes);
int best = Enumerable.Range(0, labels.Length).MaxBy(i => TensorPrimitives.CosineSimilarity(imageVector, labelVectors[i]));
USE CASES
Visual search ("shop the look"), reverse image search Duplicate and near-duplicate detection (moderation, DAM systems)
Recommendations ("more like this") Instance recognition (match a photo to a known product)
Clustering/organizing photo collections Zero-shot classification and tagging
Retrieval for multimodal RAG (find relevant diagrams or figures)
Rules (the same as for text embeddings)
SAME MODEL for the index and the queries — different models' vectors are not comparable. Record the model name/version with stored vectors; changing
models means re-embedding everything.
NORMALIZE / USE COSINE per the model's guidance; choose the vector index metric to match.
CACHE embeddings by content hash — re-embedding unchanged images is pure waste.
FILTER BY METADATA and permissions INSIDE the vector query (tenant, category, date) — see the vector search guide.
EVALUATE retrieval with real queries and labeled relevance (Recall@k), not by eyeballing a few results.
LIMITS: embeddings capture overall semantic/visual similarity, not fine detail. They can miss small text in an image, exact counts, or subtle defects —
pair them with OCR or detection when those matter.
PRIVACY: embeddings derived from sensitive images (faces, medical, documents) are sensitive data.
7. Azure AI Vision
Microsoft's managed vision services
AZURE AI VISION — IMAGE ANALYSIS 4.0 General image understanding: CAPTIONS (a sentence describing the image), DENSE CAPTIONS (regions),
TAGS, OBJECT DETECTION, PEOPLE DETECTION, SMART CROPS, and READ (OCR). One API, choose features per call.
AZURE AI VISION — MULTIMODAL Image and text embeddings for vector search (Section 6).
EMBEDDINGS
AZURE AI DOCUMENT INTELLIGENCE Document OCR, layout, prebuilt extractors (invoice, receipt, ID, ...) and custom models (Section 4).
AZURE AI FACE Face detection and, for approved use cases, verification/identification (Section 5; Limited Access applies).
AZURE OPENAI (VISION-CAPABLE MODELS) Multimodal chat models that understand images (Section 10).
AZURE AI CONTENT SAFETY Detects harmful content in images and text — useful for moderating user uploads.
CONTAINERS Some Vision and Document Intelligence capabilities are available as containers you can run in your own
environment for data-residency or disconnected scenarios (check which features and licensing apply).
Availability, regions, and feature maturity vary, and Microsoft has retired or announced retirement of older offerings (earlier Computer Vision API versions, Custom Vision, and some restricted Face features among them). Check the current service documentation and retirement notices before depending on any feature.
Image Analysis 4.0 in C
// dotnet add package Azure.AI.Vision.ImageAnalysis
using Azure;
using Azure.AI.Vision.ImageAnalysis;
var client = new ImageAnalysisClient(new Uri(endpoint), new AzureKeyCredential(key));
ImageAnalysisResult result = await client.AnalyzeAsync(
BinaryData.FromBytes(imageBytes),
VisualFeatures.Caption | VisualFeatures.Tags | VisualFeatures.Objects | VisualFeatures.People | VisualFeatures.Read,
new ImageAnalysisOptions { GenderNeutralCaption = true, Language = "en" });
Console.WriteLine($"Caption: {result.Caption.Text} ({result.Caption.Confidence:P0})");
foreach (DetectedTag tag in result.Tags.Values)
Console.WriteLine($"Tag: {tag.Name} ({tag.Confidence:P0})");
foreach (DetectedObject obj in result.Objects.Values)
Console.WriteLine($"Object: {obj.Tags[0].Name} ({obj.Tags[0].Confidence:P0}) at X={obj.BoundingBox.X}, Y={obj.BoundingBox.Y}, W={obj.BoundingBox.Width}, H={obj.BoundingBox.Height}");
foreach (DetectedPerson person in result.People.Values.Where(p => p.Confidence > 0.6))
Console.WriteLine($"Person at {person.BoundingBox.X},{person.BoundingBox.Y} ({person.Confidence:P0})");
You can pass a Uri instead of bytes when the service can fetch the image itself. Request only the visual features you need — each feature adds to the response and the bill, and some (such as captions) are available only in certain regions.
Authentication, networking, and operations
AUTH Prefer Microsoft Entra ID (DefaultAzureCredential, managed identity) over API keys; if you use keys, keep them in Key Vault.
(The SDK clients accept either.)
NETWORKING Private endpoints and virtual-network restrictions are available for enterprise deployments.
LIMITS Image size and dimension limits, supported formats, and requests-per-second quotas apply — resize before upload, and handle
HTTP 429 with backoff (see AI APIs with .NET, Sections 10-11). The SDK clients include retry policies for transient errors.
COST Billed per transaction (per feature, per image). Cache results by image hash, don't re-analyze unchanged images, and request only
needed features.
DATA Understand what the service retains and where it processes data; images can be sensitive. Use containers or private networking if policy requires.
Wire it through your own abstraction
public interface IImageAnalyzer
{
Task<ImageSummary> AnalyzeAsync(byte[] image, CancellationToken ct);
}
public record ImageSummary(string Caption, IReadOnlyList<string> Tags, IReadOnlyList<(string Label, double Confidence, int X, int Y, int W, int H)> Objects, string Text);
Hide the Azure types behind your own interface so you can swap in a self-hosted model or a different provider, add caching and resilience in one place, and unit test with a fake — the same decoupling argument made for AI services in Microsoft.Extensions.AI.
8. OpenCV Integration
OpenCV: the classic computer vision toolkit
OpenCV is a mature, high-performance library for image and video processing and "classical" computer vision: filtering, geometric transforms, edge and contour detection, feature matching, camera calibration, video I/O, background subtraction, tracking, and a DNN module that can run neural networks. In .NET you use it through OpenCvSharp (the most popular open-source wrapper) or Emgu CV (another wrapper with its own licensing terms to review).
Setup
dotnet add package OpenCvSharp4
dotnet add package OpenCvSharp4.runtime.win # native OpenCV binaries — choose the runtime package for YOUR platform:
# .runtime.win, .runtime.ubuntu.20.04-x64, .runtime.linux-arm, .runtime.osx ...
dotnet add package OpenCvSharp4.Extensions # conversions to/from System.Drawing bitmaps (Windows-oriented)
The managed package is a wrapper; native binaries must be present at runtime, which is the main deployment gotcha (especially in Docker/Linux — install the matching runtime package and any required system libraries, and test in the actual container image).
The Mat and the dispose rule
using OpenCvSharp;
// Mat is OpenCV's image/matrix type. It owns NATIVE memory that the .NET garbage collector cannot see —
// ALWAYS dispose it (using), especially in loops and servers, or you will leak memory.
using Mat image = Cv2.ImRead("photo.jpg", ImreadModes.Color); // loads as BGR (not RGB!)
using Mat gray = new();
Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY);
using Mat blurred = new();
Cv2.GaussianBlur(gray, blurred, new Size(5, 5), 0);
using Mat edges = new();
Cv2.Canny(blurred, edges, threshold1: 50, threshold2: 150);
Cv2.ImWrite("edges.png", edges);
Colors are BGR — the classic bug
OpenCV stores color images as BLUE-GREEN-RED, while most deep-learning models (and most other imaging libraries, including ImageSharp and
SkiaSharp) use RGB. Feed an unconverted BGR image to an RGB-trained model and accuracy silently drops. Convert with
Cv2.CvtColor(src, dst, ColorConversionCodes.BGR2RGB) at the boundary.
Common operations
Cv2.Resize(image, resized, new Size(640, 480)); // resize
Cv2.Rotate(image, rotated, RotateFlags.Rotate90Clockwise); // rotate
using var roi = new Mat(image, new Rect(100, 50, 200, 200)); // crop (a view into the same data)
// Find contours (shapes) in a binary image
Cv2.FindContours(binary, out Point[][] contours, out HierarchyIndex[] hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
foreach (var contour in contours.Where(c => Cv2.ContourArea(c) > 500))
Cv2.Rectangle(image, Cv2.BoundingRect(contour), Scalar.Lime, 2);
// Draw and label detections from Section 3
foreach (var d in detections)
{
var rect = new Rect((int)d.Box.X, (int)d.Box.Y, (int)d.Box.Width, (int)d.Box.Height);
Cv2.Rectangle(image, rect, Scalar.Red, 2);
Cv2.PutText(image, $"{d.Label} {d.Confidence:P0}", new Point(rect.X, Math.Max(15, rect.Y - 5)),
HersheyFonts.HersheySimplex, 0.6, Scalar.Red, 2);
}
Moving between OpenCV, bytes, and other libraries
// Encode/decode in memory (no temp files) — the way to move images over HTTP or through queues
Cv2.ImEncode(".jpg", image, out byte[] jpegBytes);
using Mat decoded = Cv2.ImDecode(jpegBytes, ImreadModes.Color);
// To feed a neural-network input tensor from a Mat, copy to a managed array and convert BGR -> RGB deliberately (not by accident)
Video: frame loops
using var capture = new VideoCapture("traffic.mp4"); // a file path, an RTSP/HTTP URL, or a camera index (0)
using var frame = new Mat();
int frameIndex = 0;
while (capture.Read(frame) && !frame.Empty())
{
// Detection is expensive: run it every Nth frame (and track in between) instead of every frame
if (frameIndex++ % 5 == 0)
{
// convert and run a detector (Section 3) ...
}
}
VIDEO PRACTICALITIES
- Decode on a worker thread; keep a small bounded queue between capture, inference, and output so a slow model drops frames instead of
accumulating latency and memory.
- Process every Nth frame or at reduced resolution for real-time budgets.
- Use hardware decoding and GPU inference when throughput matters.
- Reconnect automatically for network streams; they drop.
- Watch resource use: each frame is a large native allocation.
OpenCV's DNN module
using OpenCvSharp.Dnn;
using Net net = CvDnn.ReadNetFromOnnx("model.onnx");
using Mat blob = CvDnn.BlobFromImage(image, scaleFactor: 1 / 255.0, size: new Size(640, 640), mean: new Scalar(), swapRB: true, crop: false);
net.SetInput(blob);
using Mat output = net.Forward();
OpenCV can run many ONNX models directly (convenient for simple deployments, and for models such as YuNet face detection). For broader operator support, GPU execution providers, and performance tuning, ONNX Runtime is usually the stronger inference engine; many teams use OpenCV for image I/O and preprocessing, ONNX Runtime for inference.
When to reach for OpenCV
VIDEO AND CAMERAS capture, decode, encode, streams
GEOMETRIC / CLASSICAL CV perspective correction, deskewing, contour and shape analysis, feature matching, calibration, background subtraction
PREPROCESSING FOR OCR grayscale, thresholding, denoising, deskew (Section 4)
FAST NATIVE IMAGE OPS heavy per-pixel work where native performance matters
Prefer a managed library (Section 9) for simple resizing, format conversion, and drawing in web back ends — fewer native dependencies to deploy.
9. Image Processing APIs
Choosing a library for decoding, transforming, drawing, and encoding
Before and after any model, you decode images, orient and resize them, convert formats, and sometimes draw annotations. .NET offers several libraries, with important differences in platform support and licensing.
SixLabors.ImageSharp Fully managed, cross-platform, modern API, no native dependencies, good for web servers and containers.
Drawing lives in the separate ImageSharp.Drawing package. NOTE: it uses a "split license" — free for open-source and
qualifying small organizations, but commercial use may require a paid license; check the current terms.
SkiaSharp Bindings to Google's Skia graphics engine; fast, widely used (MAUI, Avalonia), strong 2D drawing and text rendering. Native
binaries per platform; permissive MIT license.
System.Drawing.Common GDI+ based. On .NET 6+ it is supported on WINDOWS ONLY. Don't use it for cross-platform or Linux-container services.
Magick.NET Wrapper over ImageMagick: enormous format support and many operations; native dependencies; Apache-style license.
NetVips Wrapper over libvips: very fast and memory-efficient for large images and pipelines; native dependency.
OpenCvSharp Computer vision and video, with image I/O and drawing (Section 8). BGR channel order.
Windows imaging APIs WIC/Windows.Graphics.Imaging for Windows-only apps.
ImageSharp: the everyday operations
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Processing;
// Load -> fix orientation -> resize (never enlarge) -> strip metadata -> save
using Image image = await Image.LoadAsync(inputStream);
image.Mutate(x => x
.AutoOrient() // apply the EXIF rotation phones store instead of rotating pixels
.Resize(new ResizeOptions { Size = new Size(1600, 1600), Mode = ResizeMode.Max })); // fit within 1600x1600, keep aspect ratio
image.Metadata.ExifProfile = null; // remove EXIF (GPS location, device info) before storing or sharing
await image.SaveAsJpegAsync(outputStream, new JpegEncoder { Quality = 85 });
Cross-cutting image gotchas
EXIF ORIENTATION Phone photos are often stored sideways with an orientation flag. If you ignore it, the model sees a rotated image (and OCR fails).
Apply orientation (AutoOrient) BEFORE inference.
EXIF PRIVACY Photos carry GPS coordinates, timestamps, and device details. Strip metadata before storing or publishing images you didn't create.
COLOR ORDER RGB (ImageSharp, SkiaSharp, most models) vs BGR (OpenCV). Convert deliberately.
COLOR SPACES Some images are CMYK, grayscale, 16-bit, or have alpha. Convert to a known format (e.g. Rgb24) before building tensors.
RESIZE QUALITY Choose a good resampler (bicubic/Lanczos) for downscaling; the choice can measurably affect model accuracy, and it should match
training if the model is sensitive.
MEMORY A 50-megapixel image decodes to ~150 MB of pixels. Cap dimensions BEFORE full decode (read just the header with Image.Identify) and
resize early.
THREAD SAFETY Image/Mat objects are not thread-safe; don't share one across concurrent requests.
FORMAT SUPPORT JPEG, PNG, WebP, GIF, BMP, TIFF are common; HEIC (iPhone) and RAW formats often need extra libraries — plan for them if users upload from phones.
Draw on images: ImageSharp.Drawing and SkiaSharp
// SkiaSharp: draw labeled boxes on a decoded bitmap
using SkiaSharp;
using SKBitmap bitmap = SKBitmap.Decode(imageBytes);
using var canvas = new SKCanvas(bitmap);
using var boxPaint = new SKPaint { Color = SKColors.Red, Style = SKPaintStyle.Stroke, StrokeWidth = 3 };
foreach (var d in detections)
canvas.DrawRect(d.Box.X, d.Box.Y, d.Box.Width, d.Box.Height, boxPaint);
using var image = SKImage.FromBitmap(bitmap);
using var data = image.Encode(SKEncodedImageFormat.Jpeg, 85);
await File.WriteAllBytesAsync("annotated.jpg", data.ToArray());
Validate uploaded images — they are untrusted input
// Read dimensions from the header WITHOUT decoding the whole image, and reject abusive inputs early
ImageInfo info = await Image.IdentifyAsync(stream); // throws on unrecognized formats
if (info.Width > 10_000 || info.Height > 10_000 || (long)info.Width * info.Height > 50_000_000)
return Results.BadRequest("Image dimensions are too large.");
stream.Position = 0;
Treat image uploads like any untrusted file: enforce a maximum byte size (and request-body limits); verify the actual format from content, not the file extension
or Content-Type header; limit decoded dimensions (decompression bombs — a tiny file that expands to gigabytes of pixels); process in a resource-limited
context; re-encode to a safe format rather than storing originals blindly; and scan for malware where policy requires. Keep image-decoding libraries updated —
image codecs are a historically common source of vulnerabilities.
10. Multimodal LLMs vs. Classical Computer Vision
Vision-capable chat models are now a mainstream option
Modern chat models accept images alongside text. Through Microsoft.Extensions.AI (see this series' Microsoft.Extensions.AI guide), sending an image is just another content item in a message:
using Microsoft.Extensions.AI;
var message = new ChatMessage(ChatRole.User,
[
new TextContent("Extract the vendor name, invoice number, date, and total from this invoice. Respond as JSON."),
new DataContent(imageBytes, "image/jpeg"),
]);
ChatResponse response = await chatClient.GetResponseAsync([message]);
// Or get a typed result directly
public record InvoiceFields(string Vendor, string InvoiceNumber, string Date, decimal Total);
ChatResponse<InvoiceFields> typed = await chatClient.GetResponseAsync<InvoiceFields>([message]);
InvoiceFields invoice = typed.Result; // validate it — shape is guaranteed, truth is not
What multimodal LLMs are good at
OPEN-ENDED QUESTIONS "Is anything unsafe in this photo?" "Describe what happened in this screenshot." — no model training or fixed label set.
ZERO-SHOT FLEXIBILITY New categories or extraction schemas by changing the prompt, not retraining.
MESSY DOCUMENTS Irregular layouts, handwriting, receipts photographed at angles, charts and diagrams.
REASONING OVER IMAGES Combining visual content with text instructions and context.
RAPID PROTOTYPING Proof of concept in an afternoon.
Where they fall short
HALLUCINATION They can confidently invent text, numbers, or objects that aren't in the image. For OCR-like extraction this is dangerous: a plausible but
wrong total looks exactly like a right one.
PRECISE LOCALIZATION Bounding boxes, pixel-accurate positions, and exact counting of many objects are unreliable compared with dedicated detectors.
CONSISTENCY Non-deterministic; the same image can yield different outputs.
COST AND LATENCY Each image consumes many tokens and takes seconds — painful at video frame rates or millions of images.
THROUGHPUT Rate limits and per-call pricing don't suit high-volume, real-time pipelines.
PRIVACY Images are sent to a hosted model; sensitive content (faces, IDs, medical images) raises data-protection questions.
LIMITS Image size and count per request, and resolution that may downscale small text.
Choosing
NeedPreferPrecise boxes, counts, real-time videoDedicated detector (ONNX/YOLO)High-volume, low-cost, consistent labeling of fixed categoriesTrained classifier or detectorStructured fields from standard documents with confidence scoresDocument Intelligence prebuilt/custom modelsPlain text from many images, cheaplyOCR (Vision Read / Tesseract)Flexible, varied, open-ended image questions or extraction schemasMultimodal LLMImage similarity / search at scaleEmbeddings + vector searchRapid prototype to learn what's possibleMultimodal LLM, then replace pieces with specialized models if cost/accuracy demandHybrid pipelines are often best
Classical + LLM, each doing what it's best at:
- OCR / Document Intelligence extracts the text and fields WITH confidence; an LLM interprets or normalizes them — or only handles the low-confidence cases.
- A detector finds and crops regions; an LLM describes or reads each crop.
- A cheap classifier screens images; only the uncertain ones go to the expensive multimodal model.
- An LLM proposes; deterministic code VALIDATES (totals add up, dates parse, values within ranges).
All the cautions from AI Agents and LLM Application Development apply: treat text inside images as untrusted (images can contain visual prompt injection — instructions written into a picture), validate outputs, and keep a human in the loop for consequential decisions.
11. Building a Vision Service in ASP.NET Core
A detection endpoint, with the production concerns included
// Program.cs
builder.Services.AddSingleton(sp => new ObjectDetector("models/yolov8n.onnx", CocoLabels.All)); // load the model ONCE
builder.Services.AddRateLimiter(o => o.AddPolicy("vision", ctx => RateLimitPartition.GetFixedWindowLimiter(
ctx.User.Identity?.Name ?? "anonymous", _ => new FixedWindowRateLimiterOptions { PermitLimit = 30, Window = TimeSpan.FromMinutes(1) })));
builder.WebHost.ConfigureKestrel(k => k.Limits.MaxRequestBodySize = 10_000_000); // cap upload size
var inference = new SemaphoreSlim(Environment.ProcessorCount); // bound concurrent CPU-heavy inference
app.MapPost("/detect", async (IFormFile file, ObjectDetector detector, CancellationToken ct) =>
{
if (file.Length is 0 or > 10_000_000) return Results.BadRequest("Image must be between 1 byte and 10 MB.");
await using Stream stream = file.OpenReadStream();
ImageInfo info;
try { info = await Image.IdentifyAsync(stream, ct); } // verify it's a real image; read dimensions cheaply
catch (Exception) { return Results.BadRequest("Unsupported or corrupt image."); }
if ((long)info.Width * info.Height > 50_000_000) return Results.BadRequest("Image dimensions are too large.");
stream.Position = 0;
using Image<Rgb24> image = await Image.LoadAsync<Rgb24>(stream, ct);
image.Mutate(x => x.AutoOrient()); // honor EXIF rotation BEFORE inference
await inference.WaitAsync(ct);
try
{
var detections = await Task.Run(() => detector.Detect(image), ct); // keep the request thread free; bound the work
return Results.Ok(detections.Select(d => new { d.Label, d.Confidence, d.Box.X, d.Box.Y, d.Box.Width, d.Box.Height }));
}
finally { inference.Release(); }
})
.RequireAuthorization()
.RequireRateLimiting("vision")
.DisableAntiforgery(); // an API endpoint, not a browser form post
Architecture and performance considerations
LOAD MODELS ONCE Register the inference session as a singleton; loading a model per request is slow and memory-hungry. InferenceSession.Run
is safe to call concurrently; image objects are not shared.
WARM UP The first inference is slower (graph optimization, allocations). Run a dummy inference at startup so users don't pay for it.
BOUND CONCURRENCY CPU/GPU inference is resource-intensive; limit parallel work (SemaphoreSlim) and queue the rest rather than thrashing.
ASYNC AND BACKGROUND For slow or bulk jobs (video, large batches, heavy OCR), accept the upload, enqueue a job, return an ID, and let a background worker process it
(BackgroundService / queue / Azure Functions), with status polling or a webhook/SignalR notification.
GPU Microsoft.ML.OnnxRuntime.Gpu (CUDA) or .DirectML (Windows) can accelerate inference substantially; build and test GPU container images
deliberately (drivers, CUDA/cuDNN versions).
MODEL SIZE VS. SPEED Smaller or quantized models (INT8) and lower input resolutions cut latency and memory at some accuracy cost; measure the trade-off.
BATCHING Batching several images into one inference call raises GPU throughput at the cost of per-request latency.
CACHE Key results by a hash of the image bytes (plus model version) — repeated images are common (duplicates, retries, shared files).
MODEL MANAGEMENT Version models like code; store them in blob storage or the image, record the model version with each result, and use a rolling
rollout so you can compare and roll back.
OBSERVABILITY Log latency, input sizes, confidence distributions, and error rates; export traces/metrics (OpenTelemetry). Drift in confidence
distributions is an early warning that production images have changed.
DOCKER Include native dependencies (OpenCV runtime packages, ONNX Runtime native libs) and test the actual image; keep images small.
Security and privacy for image services
UNTRUSTED UPLOADS Size/dimension limits, format verification, resource-limited processing, updated codecs (Section 9).
AUTHORIZATION Users may only analyze and retrieve THEIR images/results; scope storage and queries per user/tenant.
SENSITIVE CONTENT Images may contain faces, IDs, medical or financial documents. Minimize retention, encrypt at rest and in transit, restrict who and what
can see them, and be explicit about when images leave your environment (cloud APIs, LLMs).
EXIF AND METADATA Strip location and device data before storing or sharing.
MODERATION If users upload content others will see, screen it (for example with Azure AI Content Safety).
ADVERSARIAL INPUTS Models can be fooled by crafted images (adversarial examples); don't rely on vision output alone for security-critical decisions. Images can
also carry hidden instructions aimed at multimodal LLMs.
COSTS AND ABUSE Rate limit, cap sizes, and authenticate — an open image-analysis endpoint (especially one calling a paid API) is a cost-abuse target.
12. Evaluating Vision Systems
Pick metrics that match the task — then test on realistic data
CLASSIFICATION Accuracy (careful with imbalance), precision, recall, F1, per-class results, confusion matrix, calibration of confidence scores.
(See AI/ML Fundamentals, Section 9.)
OBJECT DETECTION IoU between predicted and true boxes; a detection is correct if the label matches and IoU exceeds a threshold (commonly 0.5).
PRECISION = correct detections / all detections; RECALL = correct detections / all true objects.
AP (average precision) per class summarizes the precision-recall curve; mAP averages across classes (and sometimes IoU thresholds).
Also check counting error and per-size performance (small objects are hardest).
OCR Character error rate (CER) and word error rate (WER) for text; FIELD-LEVEL accuracy and per-field confidence calibration for extraction;
end-to-end "is the final record correct?" rate.
FACE VERIFICATION FAR and FRR at the chosen threshold, ROC curves, and results BROKEN DOWN BY DEMOGRAPHIC GROUP and imaging condition.
EMBEDDINGS / Recall@k and MRR on labeled query-to-relevant-image pairs (see Embeddings & Vector Search and RAG, Section 12).
VISUAL SEARCH
LLM VISION Task-specific accuracy against ground truth, plus hallucination checks (does the extracted value actually appear in the image?),
consistency across repeated runs, and cost/latency.
Data practices that make evaluation honest
REPRESENTATIVE TEST SET Collect images from the REAL production environment: your cameras, lighting, devices, angles, resolutions, and edge cases (blur, glare,
occlusion, odd orientations). Models validated on clean benchmark photos routinely disappoint in the field.
SPLIT BY SOURCE Keep near-duplicates (frames from one video, shots of the same object, pages of one document) on one side of the split.
CONSISTENT LABELS Ambiguous or noisy labels cap achievable accuracy. Write labeling guidelines, measure inter-annotator agreement, and review disputed cases.
STRATIFY AND SLICE Report results by condition (day/night, indoor/outdoor, device type), by class, and by object size — averages hide failures.
FAIRNESS Where people appear, evaluate across demographic groups; large gaps are a defect even when the average looks good.
NEGATIVE EXAMPLES Include images with NONE of the target objects, and out-of-distribution images, to measure false positives and unknown handling.
FROZEN TEST SET Don't tune on it. Keep a held-out set untouched until the end, and refresh it as the world changes.
In production
CONFIDENCE DISTRIBUTIONS Track them over time; shifts signal that production images no longer match what the model was validated on.
HUMAN REVIEW QUEUE Route low-confidence or high-stakes results to people; use their corrections as new labeled data.
SAMPLED AUDIT Regularly review random samples of automated decisions, not just the flagged ones.
FEEDBACK LOOP Capture errors and overrides, label them, and fold them into the next training and evaluation set.
VERSIONED REGRESSION SUITE Re-run your evaluation set whenever you change models, thresholds, preprocessing, or a provider's model version.
COST AND LATENCY BUDGETS Track p50/p95 latency and per-image cost alongside accuracy.
13. Choosing the Right Approach
START WITH THE REQUIREMENTS, NOT THE MODEL
What decision does this feed? What does a mistake cost? Is it real-time? How many images per day? Do images contain sensitive data? Must it run offline or
inside a boundary? Are the categories common or specific to you?
THEN WALK THE LADDER, STOPPING AS EARLY AS POSSIBLE
1. A managed API handles it (Azure AI Vision, Document Intelligence) -> build in days; pay per call
2. A multimodal LLM handles it well enough -> flexible and fast to build; check cost, latency, and hallucination risk
3. A pre-trained ONNX model handles it -> run locally; no per-call fee; you own pre/postprocessing
4. You need custom accuracy on your own data -> labeled dataset, transfer learning or fine-tuning, evaluation, MLOps
THEN HARDEN
Evaluate on realistic images, set thresholds and a human-review path, add validation, secure the pipeline, monitor drift, and plan for model and service lifecycle changes.
14. Common Pitfalls
PitfallWhy it hurtsBetter approachPreprocessing that doesn't match training (size, channel order, scaling, normalization)Accuracy silently collapses with no errorCheck the model's docs; test against reference outputs from the original framework (Section 2)Mixing BGR (OpenCV) and RGB (models, ImageSharp)Colors swapped; degraded predictionsConvert deliberately at the boundary (Sections 2, 8, 9)Ignoring EXIF orientationSideways images give bad detections and OCRAutoOrient() before inference (Sections 9, 11)Forgetting to dispose Mat and imagesNative memory leaks that crash serversusing everywhere; dispose in loops (Section 8)Loading the model per requestSlow, memory-hungrySingleton inference session; warm up at startup (Section 11)Sharing an Image/Mat across threadsCorruption and racesOne per request; share only the thread-safe inference session (Section 9)Using System.Drawing.Common on LinuxWindows-only on modern .NETImageSharp, SkiaSharp, or OpenCvSharp (Section 9)Skipping NMS or the IoU/threshold tuningDuplicate boxes; too many false alarms or missesApply per-class NMS; tune thresholds on a validation set (Section 3)Not mapping boxes back through letterboxingBoxes land in the wrong place on the original imageUndo padding and scale in postprocessing (Section 3)Trusting every predictionA classifier always returns a label, even for unfamiliar imagesConfidence thresholds, an "unknown" path, human review (Section 2)Reporting accuracy on imbalanced dataA trivial majority-class model scores highPrecision, recall, F1, per-class metrics, confusion matrix (Sections 2, 12)Test images unlike productionGreat benchmarks, poor field performanceEvaluate on representative, sliced real-world images (Section 12)Train/test leakage from near-duplicate imagesInflated scores that measure memorizationSplit by source (Sections 2, 12)Feeding raw scans to OCR without cleanupLow accuracy, especially with TesseractResolution, contrast, deskew, denoise; prefer cloud/layout OCR for hard inputs (Section 4)Trusting OCR/LLM-extracted values without validationPlausible but wrong numbers flow into systemsConfidence routing plus business-rule validation (Sections 4, 10)Using a multimodal LLM for precise counting or boxesUnreliable localization; hallucinationUse a dedicated detector; use the LLM for interpretation (Section 10)Building face identification without a legal reviewBiometric laws and platform policies impose consent, retention, and sometimes bansLegal counsel first; prefer detection-only or consented 1:1 designs (Section 5)One global face-match threshold, never tested by groupUneven false accepts/rejects across demographicsValidation set per condition and subgroup; conservative thresholds (Sections 5, 12)Comparing embeddings from different modelsVectors aren't comparableOne model for index and queries; record model versions (Section 6)Unlimited uploads (size, dimensions, format)Decompression bombs, memory exhaustion, cost abuseValidate headers, cap size and dimensions, rate limit, authenticate (Sections 9, 11)Leaving EXIF metadata in stored imagesLeaks GPS location and device detailsStrip metadata before storing or sharing (Section 9)Depending on a cloud feature without checking its lifecycleRetirements and restricted features break productsRead current docs and retirement notices; hide providers behind an interface (Section 7)Running heavy inference on the request thread, unboundedThread starvation and latency spikesBound concurrency; use background jobs for slow work (Section 11)Quick Reference Table
TaskTypical .NET approachKey practiceImage classification (general)Pre-trained ONNX model + ONNX Runtime; or Azure AI Vision tagsMatch preprocessing exactly; softmax; confidence thresholdImage classification (your categories)ML.NET transfer learning, or PyTorch → ONNXRepresentative labeled data; split by source; evaluate per classObject detectionYOLO-style ONNX model; or Azure AI Vision Objects/PeopleLetterbox in, undo letterbox out; confidence + NMSOCR (photos/general)Azure AI Vision Read; Tesseract for localPreprocess; use word confidenceOCR (documents/fields)Azure AI Document Intelligence (layout, prebuilt, custom)Per-field confidence + validation + human reviewFace detectionOpenCV/DNN detector or managed detectionPrefer for blurring/cropping; low riskFace verification/identificationEmbeddings + threshold/vector search, or Azure Face (Limited Access)Legal review, consent, liveness, subgroup evaluationImage embeddingsAzure AI Vision multimodal embeddings; CLIP via ONNXSame model for index and query; cosine similarity; vector DBVisual search / dedupeEmbeddings + vector searchCache by hash; filter by tenant in the queryImage analysis (captions/tags)Azure.AI.Vision.ImageAnalysisRequest only needed features; cache; Entra ID authClassical CV and videoOpenCvSharp (+ runtime package)DisposeMat; BGR vs RGB; frame skippingResize/convert/encodeImageSharp (managed) or SkiaSharpAutoOrient, strip EXIF, cap dimensionsFlexible image understandingMultimodal LLM via IChatClient + DataContentValidate outputs; watch cost, latency, hallucinationServingASP.NET Core + singleton InferenceSessionBound concurrency; background jobs; validate uploadsQualityTask-specific metrics on a realistic, sliced test setHuman review for low confidence; monitor driftConclusion
Computer vision in .NET is no longer a research detour: a managed API can read an invoice or caption a photo in one call, an ONNX model can detect objects at video rates inside your own process, ML.NET can fine-tune a classifier on a few hundred of your images, embeddings turn "find me something that looks like this" into a vector search, and a multimodal LLM can answer open-ended questions about almost anything you show it. The real skill is choosing among those options deliberately — by accuracy needs, volume, latency, cost, data sensitivity, and the cost of a mistake — and then engineering the unglamorous parts correctly.
Those parts are where most projects succeed or fail. Preprocessing must match what the model was trained on — size, channel order, scaling, orientation — or accuracy collapses without any error message. Postprocessing must decode the model's actual output format, apply thresholds and non-maximum suppression, and map coordinates back to the original image. Native resources must be disposed, models loaded once, concurrency bounded, uploads treated as untrusted input, and metadata stripped. Outputs from OCR and multimodal models must be validated against business rules and routed to humans when confidence is low, because plausible-looking wrong answers are the dangerous kind. Face recognition deserves a legal and ethical decision before a technical one; detection-only or carefully consented, locally matched designs are usually the safer path. And above all, evaluate on images that look like production — sliced by condition, class, and (where people appear) demographic group — because a benchmark score on clean photos tells you very little about how the system will behave in the field. Build with those habits and computer vision becomes a reliable component of your .NET applications rather than a demo that stops working the moment real images arrive.
Found this useful? Feel free to star the repo, open an issue with corrections, or share the "the model worked perfectly until we noticed phone photos were all sideways" story that made the case for AutoOrient and representative test data click better than any benchmark.#dotnet #ai #programming #learning #software #coding #development #engineering #inclusive #community
Computer Vision with .NET
Exclusive: Taika Waititi’s Star Wars Movie Is “On Ice” — But There’s A Silver Lining
Taika Waititi gained a reputation for light-hearted, joyful, emotional epics with movies like Hunt for the Wilderpeople, Thor:…
#NewsBeep #News #US #USA #UnitedStates #UnitedStatesOfAmerica #Movies #Entertainment #EntertainmentNews #homepage #hp-latest #inverse-interview #sciencefiction #Scoop #StarWars
https://www.newsbeep.com/us/886670/
Exclusive: Taika Waititi’s Star Wars Movie Is “On Ice” — But There’s A Silver Lining
Taika Waititi gained a reputation for light-hearted, joyful, emotional epics with movies like Hunt for the Wilderpeople, Thor:…
#NewsBeep #News #Movies #Entertainment #EntertainmentNews #homepage #hp-latest #inverse-interview #sciencefiction #Scoop #StarWars #UK #UnitedKingdom
https://www.newsbeep.com/uk/806630/
There was tons of acorn ! Everywhere on the ground, or still in the trees. This variety really looks like the hair makeup of a rock star.
I particularly like this photo. It was starting to be late afternoon, and the light getting reddish and shining from the back creates a nice gentle mood I think.
2.5 star review of Street Fighter 2006. I did not have an entirely fun time - others did, so that's good. To me, there's a few lessons in why attempting to make a film with an intentionally "bad" aesthetic is usually a misguided idea. https://boxd.it/gQQRoZ #letterboxd
An NFL star just revealed the fast-food item die-hard Taco Bell fans covet most https://www.oregonlive.com/trending/2026/10/there-are-only-2-people-in-the-world-who-have-this-ultra-rare-taco-bell-card-and-an-nfl-star-is-one-of-them.html
@inbella To be fair to the ‘Eyeliner Veep’, there have been *so many* “failure(s) in leadership” during the #FelonsCrusade in #Iran that anybody would have trouble understanding *which failure* the ‘Gold Star Husband’ was referring to!
#Resist the #Trump #kakistocracy with #ElbowsUp 💪!
How does about 17 km per second still leave Voyager 1 about 75,000 years from the nearest star?
It's the fastest spacecraft leaving the solar system. But there's a catch: even if it were heading for Proxima Centauri, the trip would span about 40.1 trillion km.
Space has a scale problem.
https://www.europesays.com/ie/740387/ Exclusive: Taika Waititi’s Star Wars Movie Is “On Ice” — But There’s A Silver Lining #Éire #Entertainment #EntertainmentNews #homepage #HpLatest #IE #InverseInterview #Ireland #Movies #ScienceFiction #Scoop #StarWars
https://www.europesays.com/uk/1260549/ Exclusive: Taika Waititi’s Star Wars Movie Is “On Ice” — But There’s A Silver Lining #Entertainment #EntertainmentNews #homepage #HpLatest #InverseInterview #Movies #ScienceFiction #Scoop #StarWars #UK #UnitedKingdom
Okay, rant time.
Star Trek IV: The Journey Home is bad.
It's bad because it nullifies the sacrifices in the previous movies. You get Spock back, and you get a new Enterprise. It's bad because Shatner barely seems to notice the loss of his son. It's bad because a Star Trek movie shouldn't be set in 1980s San Francisco, it should be set among the stars. It's bad because the whale probe was a repurposed Rama probe for what would have been a far more interesting story put to screen.
I think people who like Star Trek IV are the kind of people who just don't like Star Trek. And when I hear someone claim that it's the best movie I just lose it. It's nothing compared to Wrath of Khan or 3 and 6.
There, rant done.
Andrew Garfield heaps praise on Tom Holland’s Sp…
Andrew Garfield has made it clear that there is nothing but admiration between the actors who have worn Spider-Man’s famous red-and-blue suit. The Amazing Spider-Man star recently opened up about Tom Holland’s portrayal of the beloved Marvel superhero, describ…
https://justpaste.in/news/andrew-garfield-heaps-praise-on-tom-hollands-spider-man-i-love-him/
Book Review: Spock Must Die! by James Blish
Author: James Blish (with J.A. Lawrence)
Title: Spock Must Die!
Publication Info: Bantam Books, 1970
Summary/Review:
The first spin-off novel for Star Trek is an interesting artifact of its time. Writing in 1969, author James Blish correctly predicts that Star Trek will return. Created before the movies and even the animated series, Blish creates a possible Star Trek future that was never followed-up upon. The crew of the Enterprise speak in an elevated language of science and philosophy which they never used on TV but feels appropriate to the crew of a science vessel. However, there are also elements of characterization that feel wrong, like Kirk calling McCoy “Doc” instead of “Bones.”
Spock Must Die! is a sequel to Errand of Mercy, the story which introduced the Klingons. In that story, the Organians – incorporeal entities – used their powers to prevent war between the Klingons and the Federation. Now the Klingons have contained the Organians and re-opened hostilities against that Federation. Caught behind enemy lines at the time the war begins, the Enterprise tries to use a transporter modification to reach the Organians. This results in accidentally creating a duplicate Spock. While using tropes of “The Enemy Within” and “Mirror, Mirror,” the duplicate Spock is unique in that everything down to the molecular level of the duplicate operates in reverse of the original. This means that the duplicate can’t even get nutrients from eating, and of course, is evil.
Thus Spock must die, but should it be Spock One or Spock Two? This book is written on the model of a TV episode and probably would’ve made an entertaining but not great episode.
Rating: ***
#BookReviews #Books #ScienceFiction #StarTrek #TVTieInYour charity acquired the knack
Of giving politics a snack.
A judge required two million paid—
Compulsory compassion! Court-made aid!
Then came that tape, that priceless class
In how a star may make a pass:
A grab, a boast, a famous face—
Consent reduced to second place.
You answered women with denials;
Then Carroll took her claims to trial.
The civil jury’s finding: true—
Sexual abuse, defamation too.
No criminal verdict. Keep that clear.
Still not your finest souvenir.
Then Stormy weather, secret pay,
And records dressed another way.
Guilty: thirty-four felony counts.
Some awkward entries in your accounts.
With Epstein, photographs remain;
They prove acquaintance, not his chain
Of crimes as yours. We’ll keep that straight:
There’s ample fact to contemplate.
Obama’s birthplace! What a quest!
The documents could get no rest.
For years you fed that bogus doubt—
A welcome mat that said KEEP OUT.
I worked in a movie theatre when The Fountain (starring Hugh Jackman) was released. I didn't get to watch it and understand what was going on. but i saw a man trying to save a tree in a biome bubble flying unfathomably fast through space towards a nebula. i saw a conquistador looking for the Tree of Life. i saw a doctor searching for a cure to cancer (he finds it ).
What i hoped this movie was about was a conquistador who found the tree of life and ate from it and so stayed alive. and he ended up living in the 21st century as a doctor trying to cure a woman he loved. and the much later maybe when the earth was dying he took the tree to space to find a new home.
not quite. but some how not far off.
the film is about a doctor trying to come to grips with the fact his wife is going to die. he desperately tries to find a cure instead. he found samples of a tree in south america that makes monkey specimen with brain cancer reverse their aging, but the tumor doesn't shrink. he finds his wife is getting worse. she cant feel hot and cold anymore. in her last night she gives him a book shes been writing and tells him the final chapter isn't written yet. she leaves it to him to finish it. 'you know. you will' she tells him when he says he doesn't know how.
moments after her death and his emotional rage at doctors who couldnt resuscitate her, he is brought news that the medicine he helped develop finally made the tumor in the monkey specimen shrink.
he begins to write the final chapter.
a conquistador who searches for the tree of life finds it. but when he eats of the sap he ends up erupting from the inside into flowers which immediately embed intocthe soul around the tree. the conquistadors life feeds the tree and refreshes it.
the man in space finds that his tree has died. hes upset. they didnt make it to the nebula in time. but the man, somehow connected to both other stories, realizes he must die so the tree can live. he sees the wife and even Queen Isabella who urge him 'you know. you will' and tell him to finish it. just like the wife told her husband about her book.
he then ascends the tree. leaps into the air to assume a lotus seating position his momentum carrying him outside the bubble, a tiny portion of which encloses around him making a new bubble he can survive in soace with. as the tree and him continue deeper into the nebula you see the heart of the dying star suddenly pull everything back in and supernova.
the nova sprays over the man who disintegrates and his particles descend upon the tree as it springs back to life
the husband wakes back up back in hos office. his wife urging him to come enjoy the first snow with him. at the start of the film, he chose instead to continue looking for a cure. he now chooses to spend the time he has left with her. they enjoy the snow, she picks a fruit off a tree and gives it to him.
later he goes back to her grave and plants it reminded of a story she told him from south america that a man told her. the man said if he dug his fathers grave up he wouldnt be there.... because they planted a seed and his father became that tree.
he looks up at the sky to see the nebula far off wink out of existence for a brief few seconds and then burst back to life.
the movie isn't an easy watch. it makes you think about the futility of keeping life going if its just going to end. but the point is rather to realize our life isn't a bubble. it is connected to everything. we must actively participate in life with each other. and when were gone, our actions and legacy continues. life continues. fighting against death isn't a winning battle. but living the life you have today is a chance to experience all there is to experience and enjoy it with others.
the movie gets a lot of hate online. the story telling could do with some improvement. but overall i think the concepts are well developed and executed. i felt the main character's pain and anguish but also felt and experienced his epiphany. and that to me is art.
not a film id watch many more times. but im glad i watched it.
btw not saying we shouldn't cure cancer. we should. 100%. mortality however is inevitable is the point i think.
i swear im not starting a movie review series on mastodon lol
At first Shy Bear went down toward the fire, that he might have light to see his way. Then he turned and moved toward the west, seeking a place where he might pass beyond the flames. But the boy could go no farther. Before him the earth was broken, and there was a deep cut in the land. He heard water moving over stones far below where it passed around the mountain. The darkness lay thick there, and he could not see how to cross. Behind him the fire grew, and it spread to the north, closing that way. The wind drove it, and the flames were many. Then the boy looked down into the chasm. He saw a small light, very bright, like the strongest star. It moved along the side of the slope, rising and falling, as if it ran. At times it went north, and at times it went south, yet always it climbed higher, and it moved very quickly. Soon the light came up to the rim. Shy Bear saw that it was worn upon the head of a person, and that person was taller than he. Then a voice was heard, and it was the voice of a woman who spoke in his own tongue, as one who had always known it.
Captain Price Actor Sends Message to Fans as Call of Duty: Modern Warfare 4 Campaign Praise Rolls in
Barry Sloane, the actor behind Call of Duty's Captain Price, has shared a message with fans as praise for Modern Warfare 4's campaign rolls in.
Early reactions to Call of Duty: Modern Warfare 4's story mode have filled social media feeds in the first 24 hours since early access players dived in – and most of them seem to be quite positive. Fans online have called it one of the more "brutal" and "intense" campaigns the series has ever seen, with many going as far as to say it holds its own against classic stories featured in games like the original Modern Warfare 2 and Black Ops.
It appears to be a winner for publisher Activision and developer Infinity Ward that critics like, too. While Steam reviews paint a "Very Positive" picture, IGN awarded this year's set of story missions an 8/10. Our reviewer said the Modern Warfare 4 campaign made them "feel something for the series again," adding that it managed to send the reboot saga series out "on a high note."
"The MW4 campaign was a 10/10 for me, they made a good story and ended it," one recent Steam review said. "Damn near almost cried at the end LOL."
As reviews continue to trickle in, many have taken the time to praise Sloane's work as Captain Price, specifically. The star behind Activision's most recent incarnation of the Task Force 141 leader took to social media to respond to the "kind words" he's received.
"Thank you for all the kind words," he said. "I see them. I read them. And I am grateful."
As Infinity Ward sought to end this Modern Warfare storyline with the 2026 Call of Duty game, it should come as no surprise to see that the developers took big swings in its story. With that said, full-on, untagged Modern Warfare 4 campaign spoilers have already started to show up across feeds, too. There's not much Activision can do about that, but Sloane used his message as an opportunity to ask fans to keep unfiltered reactions to themselves, at least for now.
"Remember," he continued, "let's allow people to enjoy the game in their own time. No spoilers. Bravo 6 – Dark."
Call of Duty: Modern Warfare 4's campaign is out now for early access players. Its DMZ mode will drop Tuesday, October 20, with the full release set to follow Friday, October 23, for PC, Nintendo Switch 2, PlayStation 5, and Xbox Series X/S. For a full debrief on the events of the FPS franchise's latest story mode, click here. You can also check out …