Oluşan hata payını hesaplamaya girdi olarak ekleyerek düzensiz sistemleri düzenli hale getirmeye çalışır.
Kalman filitresi sensör füzyonu ve veri füzyonu için kullanılır. Tipik olarak, gerçek zamanlı sistemler bir sistemin durumunu elde etmek için tek bir ölçüm yapmak yerine birçok ardışık ölçüm üretir. Bu birçok ölçüm daha sonra o zaman anında sistemin durumunu üretmek için matematiksel olarak birleştirilir. Örnek bir uygulama olarak, bir kamyonun yerini hassas olarak belirleme problemini düşünün. Kamyona pozisyon tahminini birkaç metre ile sağlayabilen bir GPS birimi takılabilir. GPS tahminleri gürültülüdür; okumalar, her zaman gerçek pozisyonun birkaç metre yakınında olmasına rağmen, hızlıca etrafta zıplayabilir. Kamyonun pozisyonu, direksiyon dönüşleri ve direksiyonun açısını izleyerek, hızı ve yönü zamana göre entegre ederek de tahmin edilebilir. Bu teknik parakete hesabı olarak bilinir. Tipik olarak, parakete hesabı kamyonun yeri hakkında çok yumuşak bir tahmin sağlayacaktır, ancak küçük hatalar biriktikçe sapacaktır. Ayrıca, kamyon'un fizik kurallarını takip etmesi de beklenir, yani pozisyonunun hızıyla orantılı olarak değişmesi beklenir. Bu örnekte, Kalman filitresinin iki ayrı fazda çalıştığı düşünülebilir: tahmin et ve güncelle. Tahmin etme fazında, kamyonun eski yeri Newton'ın hareket yasaları göre değiştirilecek (dinamik veya "durum değiştirme" modeli) artı gaz pedalı ve direksiyon tarafından üretilen tüm değişiklikler katılacak. Sadece bir pozisyon tahmini hesaplanmayacak, ancak yeni bir kovaryans da hesaplanacaktır. Belki de kovaryans kamyonun hızı ile orantılıdır; çünkü yüksek hızlarda parakete hesabının hassaslığından daha az eminiz ancak çok yavaş hareket ettiğinde baya eminiz. Sonra, güncelleme fazında, kamyonun pozisyonunun bir ölçümü GPS biriminden alınır. Bu ölçümle beraber bir miktar belirsizlik de gelir ve bunun koyaryansının önceki fazdan gelen tahminin kovaryansına oranı, yeni ölçümün güncellenen tahmini ne kadar etkileyeceğini belirler. İdeal olarak, parakete hesabı tahminleri gerçek pozisyondan uzaklaştıkça, GPS ölçümleri pozisyon tahminlerini gerçek pozisyona doğru, hızlıca değişim ve gürültülü olmayacak şekilde çeker. Yüklenen herhangi bir cismi bulma kodu:
function kalman_eklem_bulma() clear; close all; % video olarak alınıp pencere boyutu ayarlanıyor. obj = setupSystemObjects(); tracks = initializeTracks(); % boş bir dizi oluşturur. nextId = 1; % sonraki bulunacak nokta % Her bir video frame için aşağıdaki işlem tekrarlanmaktadır. while ~isDone(obj.reader) frame = readFrame(); [centroids, bboxes, mask] = detectObjects(frame); predictNewLocationsOfTracks(); [assignments, unassignedTracks, unassignedDetections] = ... detectionToTrackAssignment(); updateAssignedTracks(); updateUnassignedTracks(); deleteLostTracks(); createNewTracks(); displayTrackingResults(); end function obj = setupSystemObjects() % video yükleniyor. obj.reader = vision.VideoFileReader('salto.avi'); % gösterilecek figür(pencere) ayarlanıyor. obj.maskPlayer = vision.VideoPlayer('Position', [50, 200, 700, 600]); % [centroids, bboxes, mask] değerlerini bulmak için kullanılır. obj.blobAnalyser = vision.BlobAnalysis('BoundingBoxOutputPort', true, ... 'AreaOutputPort', true, 'CentroidOutputPort', true, ... 'MinimumBlobArea', 1); end % tracks dizisinin değerleri: % % * |id| : her bir noktanın id bilgisi % * |bbox| : nesneleri gösterecek yazının sınırları bilgisi % * |kalmanFilter| : hareket bazlı izlemek için kullanılan kalman % * |age| : ilk tespit edilmesinden bu yana frame sayısı % * |totalVisibleCount| : görünen parça tespit edilen toplam frame sayısı % * |consecutiveInvisibleCount| : nokta tespit edilmeyen ardışık frame sayısı function tracks = initializeTracks() % create an empty array of tracks tracks = struct(... 'id', {}, ... 'bbox', {}, ... 'kalmanFilter', {}, ... 'age', {}, ... 'totalVisibleCount', {}, ... 'consecutiveInvisibleCount', {}); end %% videonun bir sonraki frame alma function frame = readFrame() frame = obj.reader.step(); end %% noktarı bulma % videonun her bir frame için tek bir framede % centroids(bulunan noktaların merkez bilgisi) % bboxes(nesneleri gösterecek yazının sınırları bilgisi) % mask(framemin gri modda temizlenmiş hali) function [centroids, bboxes, mask] = detectObjects(frame) %gri moda çevirme I = rgb2gray(frame); %eşik değeri belirleme [level EM] = graythresh(I); %belirlenen eşik değerine göre gereksiz noktaları temizleme mask = im2bw(I,EM); mask = medfilt2(mask,[1 1]); % 4 piksel den küçük kod topluluklarını sil mask = bwareaopen(mask,4); % blobAnalyser kullanarak [centroids, bboxes, mask] değerlerini % bulma [~, centroids, bboxes] = obj.blobAnalyser.step(mask); end %% Mevcut parçalardan yeni yerin tahmini % kalman filtresi kullanılarak geçmişteki nokların bilgisinden faydalanarak % framedeki noktaların yerlerini tespit etme. function predictNewLocationsOfTracks() for i = 1:length(tracks) bbox = tracks(i).bbox; % noktanın mevcut konumunu kalman ile tahmin etme. predictedCentroid = predict(tracks(i).kalmanFilter); % sınırı belirlenmiş kutu(bbox)kullanılarak merkezi konumunu tahim. predictedCentroid = int32(predictedCentroid) - bbox(3:4) / 2; tracks(i).bbox = [predictedCentroid, bbox(3:4)]; end end %% Assign Detections to Tracks % Assigning object detections in the current frame to existing tracks is % done by minimizing cost. The cost is defined as the negative % log-likelihood of a detection corresponding to a track. % % The algorithm involves two steps: % % Step 1: Compute the cost of assigning every detection to each track using % the |distance| method of the |vision.KalmanFilter| System object. The % cost takes into account the Euclidean distance between the predicted % centroid of the track and the centroid of the detection. It also includes % the confidence of the prediction, which is maintained by the Kalman % filter. The results are stored in an MxN matrix, where M is the number of % tracks, and N is the number of detections. % % Step 2: Solve the assignment problem represented by the cost matrix using % the |assignDetectionsToTracks| function. The function takes the cost % matrix and the cost of not assigning any detections to a track. % % The value for the cost of not assigning a detection to a track depends on % the range of values returned by the |distance| method of the % |vision.KalmanFilter|. This value must be tuned experimentally. Setting % it too low increases the likelihood of creating a new track, and may % result in track fragmentation. Setting it too high may result in a single % track corresponding to a series of separate moving objects. % % The |assignDetectionsToTracks| function uses the Munkres' version of the % Hungarian algorithm to compute an assignment which minimizes the total % cost. It returns an M x 2 matrix containing the corresponding indices of % assigned tracks and detections in its two columns. It also returns the % indices of tracks and detections that remained unassigned. function [assignments, unassignedTracks, unassignedDetections] = ... detectionToTrackAssignment() nTracks = length(tracks); nDetections = size(centroids, 1); % Compute the cost of assigning each detection to each track. cost = zeros(nTracks, nDetections); for i = 1:nTracks cost(i, :) = distance(tracks(i).kalmanFilter, centroids); end % Solve the assignment problem. costOfNonAssignment = 20; [assignments, unassignedTracks, unassignedDetections] = ... assignDetectionsToTracks(cost, costOfNonAssignment); end %% Update Assigned Tracks % The |updateAssignedTracks| function updates each assigned track with the % corresponding detection. It calls the |correct| method of % |vision.KalmanFilter| to correct the location estimate. Next, it stores % the new bounding box, and increases the age of the track and the total % visible count by 1. Finally, the function sets the invisible count to 0. function updateAssignedTracks() numAssignedTracks = size(assignments, 1); for i = 1:numAssignedTracks trackIdx = assignments(i, 1); detectionIdx = assignments(i, 2); centroid = centroids(detectionIdx, :); bbox = bboxes(detectionIdx, :); % Correct the estimate of the object's location % using the new detection. correct(tracks(trackIdx).kalmanFilter, centroid); % Replace predicted bounding box with detected % bounding box. tracks(trackIdx).bbox = bbox; % Update track's age. tracks(trackIdx).age = tracks(trackIdx).age + 1; % Update visibility. tracks(trackIdx).totalVisibleCount = ... tracks(trackIdx).totalVisibleCount + 1; tracks(trackIdx).consecutiveInvisibleCount = 0; end end %% Update Unassigned Tracks % Mark each unassigned track as invisible, and increase its age by 1. function updateUnassignedTracks() for i = 1:length(unassignedTracks) ind = unassignedTracks(i); tracks(ind).age = tracks(ind).age + 1; tracks(ind).consecutiveInvisibleCount = ... tracks(ind).consecutiveInvisibleCount + 1; end end %% Delete Lost Tracks % The |deleteLostTracks| function deletes tracks that have been invisible % for too many consecutive frames. It also deletes recently created tracks % that have been invisible for too many frames overall. function deleteLostTracks() if isempty(tracks) return; end invisibleForTooLong = 20; ageThreshold = 8; % Compute the fraction of the track's age for which it was visible. ages = [tracks(:).age]; totalVisibleCounts = [tracks(:).totalVisibleCount]; visibility = totalVisibleCounts ./ ages; % Find the indices of 'lost' tracks. lostInds = (ages < ageThreshold & visibility < 0.6) | ... [tracks(:).consecutiveInvisibleCount] >= invisibleForTooLong; % Delete lost tracks. tracks = tracks(~lostInds); end %% Create New Tracks % Create new tracks from unassigned detections. Assume that any unassigned % detection is a start of a new track. In practice, you can use other cues % to eliminate noisy detections, such as size, location, or appearance. function createNewTracks() centroids = centroids(unassignedDetections, :); bboxes = bboxes(unassignedDetections, :); for i = 1:size(centroids, 1) centroid = centroids(i,:); bbox = bboxes(i, :); % Create a Kalman filter object. kalmanFilter = configureKalmanFilter('ConstantVelocity', ... centroid, [200, 50], [100, 25], 100); % Create a new track. newTrack = struct(... 'id', nextId, ... 'bbox', bbox, ... 'kalmanFilter', kalmanFilter, ... 'age', 1, ... 'totalVisibleCount', 1, ... 'consecutiveInvisibleCount', 0); % Add it to the array of tracks. tracks(end + 1) = newTrack; % Increment the next id. nextId = nextId + 1; end end %% Tespit edilen noktaları işaretleme ve yazı ile belirme % her bir frame için tespit veya tahmin edilen noktalar işaretlenmektedir % bu noktaların ne olduğu yazılmaktadır. function displayTrackingResults() % kalibre etme dizisi vucut = {'Omuz', 'Ayak Bilegi', 'Kalca', 'Diz', 'Ayak Ucu', 'Dirsek', 'El Bilegi'}; % Convert the frame and the mask to uint8 RGB. frame = im2uint8(frame); mask = uint8(repmat(mask, [1, 1, 3])) .* 255; minVisibleCount = 3; if ~isempty(tracks) % Noisy detections tend to result in short-lived tracks. % Only display tracks that have been visible for more than % a minimum number of frames. reliableTrackInds = ... [tracks(:).totalVisibleCount] > minVisibleCount; reliableTracks = tracks(reliableTrackInds); % Display the objects. If an object has not been detected % in this frame, display its predicted bounding box. if ~isempty(reliableTracks) % Get bounding boxes. bboxes = cat(1, reliableTracks.bbox); % Get ids. ids = int32([reliableTracks(:).id]); % Create labels for objects indicating the ones for % which we display the predicted rather than the actual % location. labels = cellstr(vucut(ids')); predictedTrackInds = ... [reliableTracks(:).consecutiveInvisibleCount] > 0; isPredicted = cell(size(labels)); isPredicted(predictedTrackInds) = {' <Tahmin Edildi>'}; labels = strcat(labels, isPredicted); % Draw the objects on the frame. frame = insertObjectAnnotation(frame, 'rectangle', ... bboxes, labels); % Draw the objects on the mask. mask = insertObjectAnnotation(mask, 'rectangle', ... bboxes, labels); end end % Display the mask and the frame. obj.maskPlayer.step(mask); end %% Summary % This example created a motion-based system for detecting and % tracking multiple moving objects. Try using a different video to see if % you are able to detect and track objects. Try modifying the parameters % for the detection, assignment, and deletion steps. % % The tracking in this example was solely based on motion with the % assumption that all objects move in a straight line with constant speed. % When the motion of an object significantly deviates from this model, the % example may produce tracking errors. Notice the mistake in tracking the % person labeled #12, when he is occluded by the tree. % % The likelihood of tracking errors can be reduced by using a more complex % motion model, such as constant acceleration, or by using multiple Kalman % filters for every object. Also, you can incorporate other cues for % associating detections over time, such as size, shape, and color. displayEndOfDemoMessage(mfilename) end