diff --git a/dbm-service/src/main/java/com/devbeh/DbmProperties.java b/dbm-service/src/main/java/com/devbeh/DbmProperties.java
index d0c897e2dcc82f58f89a7da2931b615ed09ef263..7fbc39b3269af9c62378fce9aaf1569d137c51ec 100644
--- a/dbm-service/src/main/java/com/devbeh/DbmProperties.java
+++ b/dbm-service/src/main/java/com/devbeh/DbmProperties.java
@@ -115,6 +115,12 @@ public class DbmProperties
      */
     private String perceptionResultDirPath;
 
+    /**
+     * Путь к директории, в которую будут записаны файлы атомарных знаний или стая строка (null), если сбор таких
+     * файлов не требуется.
+     */
+    private String atomicKnowledgeDirPath;
+
     /**
      * Идентификатор начального кадра, с которого необходимо формировать результирующее видео.
      */
@@ -455,6 +461,18 @@ public class DbmProperties
     }
 
 
+    public String getAtomicKnowledgeDirPath()
+    {
+        return atomicKnowledgeDirPath;
+    }
+
+
+    public void setAtomicKnowledgeDirPath(String atomicKnowledgeDirPath)
+    {
+        this.atomicKnowledgeDirPath = atomicKnowledgeDirPath;
+    }
+
+
     public long getPerceptionInitialConsumedFrameId()
     {
         return perceptionInitialConsumedFrameId;
@@ -649,6 +667,13 @@ public class DbmProperties
 
     public static class FileVideoProviderProperties
     {
+        /**
+         * Неотрицательный идентификатор видео или -1, если идентификатор должен быть выбран в соответствии с
+         * порядковым номером. Если хотя бы один видеопоток имеет идентификатор, отличный от -1 (заданный вручную),
+         * для всех видеопотоков идентификатор также должен быть задан вручную.
+         */
+        private int videoId = -1;
+
         /**
          * Имя потока видеозаписи.
          */
@@ -681,11 +706,28 @@ public class DbmProperties
         private float cameraHeightMm;
 
         /**
-         * Путь к файлу (в формате .pl), содержащему специфичные для конкретного видеопотока знания (например, с описанием
-         * положения статических объектов) или null.
+         * Путь к файлу (в формате .pl), содержащему специфичные для конкретного видеопотока знания (например, с
+         * описанием положения статических объектов) или null.
          */
         private String cameraKbRulesFilePath = null;
 
+        /**
+         * Если установлено true, топики с состоянием БЗ и результатами детектирования будут удалены.
+         */
+        private boolean clearKbState = false;
+
+
+        public int getVideoId()
+        {
+            return videoId;
+        }
+
+
+        public void setVideoId(int videoId)
+        {
+            this.videoId = videoId;
+        }
+
 
         public String getName()
         {
@@ -769,5 +811,17 @@ public class DbmProperties
         {
             this.cameraKbRulesFilePath = cameraKbRulesFilePath;
         }
+
+
+        public boolean isClearKbState()
+        {
+            return clearKbState;
+        }
+
+
+        public void setClearKbState(boolean clearKbState)
+        {
+            this.clearKbState = clearKbState;
+        }
     }
 }
diff --git a/dbm-service/src/main/java/com/devbeh/DeviantBehaviourManagerStarter.java b/dbm-service/src/main/java/com/devbeh/DeviantBehaviourManagerStarter.java
index f1b85e70e06039497390e00043d3d22efc690c31..9c72d5513defea431f7ab8e8213f3cf8823b7f75 100644
--- a/dbm-service/src/main/java/com/devbeh/DeviantBehaviourManagerStarter.java
+++ b/dbm-service/src/main/java/com/devbeh/DeviantBehaviourManagerStarter.java
@@ -37,6 +37,7 @@ import org.apache.kafka.common.Node;
 import org.apache.kafka.common.config.ConfigResource;
 import org.apache.kafka.common.errors.InvalidPartitionsException;
 import org.apache.kafka.common.errors.TopicExistsException;
+import org.apache.kafka.common.errors.UnknownTopicOrPartitionException;
 import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -131,8 +132,22 @@ public class DeviantBehaviourManagerStarter implements InitializingBean, Disposa
                 "General kb rules file '" + prop.getGeneralKbRulesFilePath() + "' can't be read");
 
         Set<String> videoStreamNames = new HashSet<>();
+        boolean manualPartition = false;
+        boolean automaticPartition = false;
         for (DbmProperties.FileVideoProviderProperties fvpProp : prop.getFileVideoProviders())
         {
+            checkCondition(fvpProp.getVideoId() >= -1, "dbm.file-video-providers[].video-id "
+                    + "must be specified");
+
+            if (fvpProp.getVideoId() == -1)
+            {
+                automaticPartition = true;
+            }
+            else if (fvpProp.getVideoId() >= 0)
+            {
+                manualPartition = true;
+            }
+
             checkCondition(!Utils.isEmpty(fvpProp.getName()), "dbm.file-video-providers[].name must be specified");
             checkCondition(videoStreamNames.add(fvpProp.getName()),
                     "dbm.file-video-providers[].name must be unique, but got duplicate " + fvpProp.getName());
@@ -151,6 +166,17 @@ public class DeviantBehaviourManagerStarter implements InitializingBean, Disposa
 
             fvpProp.setMaxFps(fvpProp.getMaxFps() > 0 ? fvpProp.getMaxFps() : prop.getMaxFps());
         }
+
+        checkCondition(!(manualPartition && automaticPartition), "All video id's must be either specified "
+                + "manually or assigned automatically");
+
+        if (automaticPartition)
+        {
+            for (int i = 0; i < prop.getFileVideoProviders().size(); i++)
+            {
+                prop.getFileVideoProviders().get(i).setVideoId(i);
+            }
+        }
     }
 
 
@@ -169,9 +195,10 @@ public class DeviantBehaviourManagerStarter implements InitializingBean, Disposa
         DbmProperties prop = dbmProperties();
         validateAndFixProperties(prop);
 
-        // Создаем необходимые партиции
+        // Создаем необходимые партиции и очищаем данные KB, при необходимости
 
-        int partitionsCount = prop.getFileVideoProviders().size();
+        int partitionsCount = prop.getFileVideoProviders().stream()
+                .mapToInt(DbmProperties.FileVideoProviderProperties::getVideoId).max().orElse(-1) + 1;
         if (partitionsCount == 0)
         {
             return;
@@ -243,6 +270,32 @@ public class DeviantBehaviourManagerStarter implements InitializingBean, Disposa
                     }
                 }
             }
+
+            // При необходимости, удаляем данные KB
+            Set<String> topicsToDelete = new HashSet<>();
+            for (DbmProperties.FileVideoProviderProperties fvpProp : prop.getFileVideoProviders())
+            {
+                if (fvpProp.isClearKbState())
+                {
+                    topicsToDelete.add(prop.getKbStateTopicPrefix() + fvpProp.getVideoId());
+                    topicsToDelete.add(prop.getDevBehDetectionsTopicPrefix() + fvpProp.getVideoId());
+                }
+            }
+
+            if (!topicsToDelete.isEmpty())
+            {
+                try
+                {
+                    ac.deleteTopics(topicsToDelete).all().get();
+                }
+                catch (ExecutionException e)
+                {
+                    if (!(e.getCause() instanceof UnknownTopicOrPartitionException))
+                    {
+                        throw e;
+                    }
+                }
+            }
         }
 
         // Инициализируем конвейеры обработки видеозаписей
@@ -250,23 +303,20 @@ public class DeviantBehaviourManagerStarter implements InitializingBean, Disposa
         List<Actor> managers = new ArrayList<>();
         MetricService metricService = new MetricService(metricRegistry);
 
-        int videoId = -1;
         for (DbmProperties.FileVideoProviderProperties fvpProp : prop.getFileVideoProviders())
         {
-            videoId++;
-
             // Теоретически, если два потока одновременно запустят остановку pipeline, они могут заджойниться друг на
             // друге, но считаем, что это маловероятно, и если такое возникнет, сработает ограничение максимального
             // времени ожидания
             PipelineStopper pipelineStopper = new PipelineStopper();
 
-            CompletableFuture<Double> fpsFuture = new CompletableFuture<>();
+            CompletableFuture<VideoInfo> fpsFuture = new CompletableFuture<>();
 
             // Создаем компонент визуализации результатов детектирования
             FileVideoProvider dvmVideoProvider = new FileVideoProvider(fvpProp.getFilePath(), fvpProp.getMaxFps());
             DetectionsVisualizationManager detectionsVisualizationManager = new DetectionsVisualizationManager(
-                    fvpProp.getName(), videoId, prop.getBootstrapServer(), prop.getUsername(), prop.getPassword(),
-                    prop.getDevBehDetectionsTopicPrefix(), prop.getDevBehDetectionsDirPath(),
+                    fvpProp.getName(), fvpProp.getVideoId(), prop.getBootstrapServer(), prop.getUsername(),
+                    prop.getPassword(), prop.getDevBehDetectionsTopicPrefix(), prop.getDevBehDetectionsDirPath(),
                     prop.getDevBehDetectionsStartFrameId(), dvmVideoProvider, prop.getMaxFrameSizePixels(),
                     pipelineStopper::stop, metricService);
 
@@ -277,44 +327,48 @@ public class DeviantBehaviourManagerStarter implements InitializingBean, Disposa
                     pipelineStopper::stop, metricService);
 
             // Создание менеджера базы знаний
-            KBManager kbManager = new KBManager(fvpProp.getName(), videoId, prop.getBootstrapServer(),
+            KBManager kbManager = new KBManager(fvpProp.getName(), fvpProp.getVideoId(), prop.getBootstrapServer(),
                     prop.getUsername(), prop.getPassword(), prop.getKbStateTopicPrefix(),
                     prop.getDevBehDetectionsTopicPrefix(), prop.getKbHistoryIntervalSec(), prop.getInferencePeriodSec(),
                     prop.getDevBehIgnorePeriodSec(), fpsFuture, prop.getMaxQueuedFrames(), prop.getKbWorkerJarPath(),
                     prop.getKbWorkerMemory(), prop.getLibjplJavaLibraryPath(), prop.getGeneralKbRulesFilePath(),
-                    fvpProp.getCameraKbRulesFilePath(), prop.getMaxActionDurationSec(),
-                    prop.getMaxChildSkeletonLengthMm(), pipelineStopper::stop, metricService);
+                    fvpProp.getCameraKbRulesFilePath(), prop.getAtomicKnowledgeDirPath(),
+                    prop.getMaxActionDurationSec(), prop.getMaxChildSkeletonLengthMm(), pipelineStopper::stop,
+                    metricService);
 
             // Создание менеджера детектирования действий
-            ActionsManager actionsManager = new ActionsManager(fvpProp.getName(), videoId, prop.getBootstrapServer(),
-                    prop.getUsername(), prop.getPassword(), prop.getActionsRequestTopicName(),
-                    prop.getActionsResponseTopicPrefix(),  prop.getMaxQueuedFrames(), prop.getMaxProcessingFrames(),
-                    kbManager, perceptionVisualizationManager, pipelineStopper::stop, metricService);
+            ActionsManager actionsManager = new ActionsManager(fvpProp.getName(), fvpProp.getVideoId(),
+                    prop.getBootstrapServer(), prop.getUsername(), prop.getPassword(),
+                    prop.getActionsRequestTopicName(), prop.getActionsResponseTopicPrefix(),  prop.getMaxQueuedFrames(),
+                    prop.getMaxProcessingFrames(), kbManager, perceptionVisualizationManager, pipelineStopper::stop,
+                    metricService);
 
             // Создание менеджера оценки расстояния до объектов
             DistanceEstimationManager distanceEstimationManager = new DistanceEstimationManager(fvpProp.getName(),
-                    videoId, fvpProp.getCameraHeightMm(), fvpProp.getFocalLengthMm(), fvpProp.getPixelSizeMm(),
-                    prop.getBootstrapServer(), prop.getUsername(), prop.getPassword(),
+                    fvpProp.getVideoId(), fvpProp.getCameraHeightMm(), fvpProp.getFocalLengthMm(),
+                    fvpProp.getPixelSizeMm(), prop.getBootstrapServer(), prop.getUsername(), prop.getPassword(),
                     prop.getDistanceRequestTopicName(), prop.getDistanceResponseTopicPrefix(),
                     prop.getBoxContactPointLiftPercent(), prop.getMaxQueuedFrames(), prop.getMaxProcessingFrames(),
                     actionsManager, kbManager, perceptionVisualizationManager, pipelineStopper::stop, metricService);
 
             // Создание менеджера оценки трехмерного скелета людей
-            PoseEstimationManager poseEstimationManager = new PoseEstimationManager(fvpProp.getName(), videoId,
-                    prop.getBootstrapServer(), prop.getUsername(), prop.getPassword(), prop.getPoseRequestTopicName(),
-                    prop.getPoseResponseTopicPrefix(), prop.getMaxQueuedFrames(), prop.getMaxProcessingFrames(),
-                    distanceEstimationManager, perceptionVisualizationManager, pipelineStopper::stop, metricService);
+            PoseEstimationManager poseEstimationManager = new PoseEstimationManager(fvpProp.getName(),
+                    fvpProp.getVideoId(), prop.getBootstrapServer(), prop.getUsername(), prop.getPassword(),
+                    prop.getPoseRequestTopicName(), prop.getPoseResponseTopicPrefix(), prop.getMaxQueuedFrames(),
+                    prop.getMaxProcessingFrames(), distanceEstimationManager, perceptionVisualizationManager,
+                    pipelineStopper::stop, metricService);
 
             // Создание менеджера отслеживания людей и объектов
-            TrackingManager trackingManager = new TrackingManager(fvpProp.getName(), videoId, prop.getBootstrapServer(),
-                    prop.getUsername(), prop.getPassword(), prop.getTrackingRequestTopicName(),
-                    prop.getTrackingResponseTopicPrefix(), prop.getTrackingManagerStateTopicPrefix(),
-                    prop.getMaxOccludedDurationSec(), fpsFuture, prop.getMaxQueuedFrames(),
-                    prop.getMaxProcessingFrames(), distanceEstimationManager, poseEstimationManager, actionsManager,
-                    kbManager, perceptionVisualizationManager, pipelineStopper::stop, metricService);
+            TrackingManager trackingManager = new TrackingManager(fvpProp.getName(), fvpProp.getVideoId(),
+                    prop.getBootstrapServer(), prop.getUsername(), prop.getPassword(),
+                    prop.getTrackingRequestTopicName(), prop.getTrackingResponseTopicPrefix(),
+                    prop.getTrackingManagerStateTopicPrefix(), prop.getMaxOccludedDurationSec(), fpsFuture,
+                    prop.getMaxQueuedFrames(), prop.getMaxProcessingFrames(), distanceEstimationManager,
+                    poseEstimationManager, actionsManager, kbManager, perceptionVisualizationManager,
+                    pipelineStopper::stop, metricService);
 
             // Создание менеджера детектирования людей и объектов
-            DetectionManager detectionManager = new DetectionManager(fvpProp.getName(), videoId,
+            DetectionManager detectionManager = new DetectionManager(fvpProp.getName(), fvpProp.getVideoId(),
                     prop.getBootstrapServer(), prop.getUsername(), prop.getPassword(),
                     prop.getDetectionRequestTopicName(), prop.getDetectionResponseTopicPrefix(),
                     prop.getMaxQueuedFrames(), prop.getMaxProcessingFrames(), trackingManager, poseEstimationManager,
diff --git a/dbm-service/src/main/java/com/devbeh/VideoInfo.java b/dbm-service/src/main/java/com/devbeh/VideoInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..7beb867cb36e0ea5e717d43634f798286afaa80b
--- /dev/null
+++ b/dbm-service/src/main/java/com/devbeh/VideoInfo.java
@@ -0,0 +1,20 @@
+package com.devbeh;
+
+
+/**
+ * Инициализируется менеджером видеопотока.
+ */
+public class VideoInfo
+{
+    public final int frameHeight;
+    public final int frameWidth;
+    public final double fps;
+
+
+    public VideoInfo(int frameHeight, int frameWidth, double fps)
+    {
+        this.frameHeight = frameHeight;
+        this.frameWidth = frameWidth;
+        this.fps = fps;
+    }
+}
diff --git a/dbm-service/src/main/java/com/devbeh/managers/DetectionsVisualizationManager.java b/dbm-service/src/main/java/com/devbeh/managers/DetectionsVisualizationManager.java
index e41da4e2ff622a447e6ac930845787c6a53c66d3..2491ea09e1eb815266a10ff5b4b5264c35189db8 100644
--- a/dbm-service/src/main/java/com/devbeh/managers/DetectionsVisualizationManager.java
+++ b/dbm-service/src/main/java/com/devbeh/managers/DetectionsVisualizationManager.java
@@ -286,8 +286,8 @@ public class DetectionsVisualizationManager extends Actor
             }
         }
 
-        double fps = videoProvider.initFps();
-        videoProvider.initFrameParameters(entry.getStartFrameId(), maxFrameSizePixels);
+        videoProvider.initVideoInfo(maxFrameSizePixels);
+        videoProvider.initInitialFrameId(entry.getStartFrameId());
         try
         {
             FFmpegFrameRecorder frameRecorder = new FFmpegFrameRecorder(resultVideoFile,
@@ -295,7 +295,7 @@ public class DetectionsVisualizationManager extends Actor
             try (frameRecorder)
             {
                 frameRecorder.setFormat("mp4");
-                frameRecorder.setFrameRate(fps);
+                frameRecorder.setFrameRate(videoProvider.getFps());
                 frameRecorder.setVideoQuality(0);
                 frameRecorder.start();
 
diff --git a/dbm-service/src/main/java/com/devbeh/managers/KBManager.java b/dbm-service/src/main/java/com/devbeh/managers/KBManager.java
index 54ad668114bb4e165a9c536d9c11284992996cae..5798ac0c4816f33822233630777329fb653a0bd1 100644
--- a/dbm-service/src/main/java/com/devbeh/managers/KBManager.java
+++ b/dbm-service/src/main/java/com/devbeh/managers/KBManager.java
@@ -3,6 +3,7 @@ package com.devbeh.managers;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -29,6 +30,7 @@ import com.devbeh.Actor;
 import com.devbeh.DetectionClass;
 import com.devbeh.MetricService;
 import com.devbeh.Utils;
+import com.devbeh.VideoInfo;
 import com.devbeh.commondata.DevBehDetections;
 import com.devbeh.commondata.Empty;
 import com.devbeh.commondata.KBEntry;
@@ -131,7 +133,7 @@ public class KBManager extends Actor implements TrackingConsumer, DistanceDataCo
     /**
      * Предоставляет fps обрабатываемого видеопотока. Используется для создания результирующего видео.
      */
-    private final Future<Double> fpsFuture;
+    private final Future<VideoInfo> fpsFuture;
 
     /**
      * Путь к jar компонента-обертки над базой знаний.
@@ -158,6 +160,11 @@ public class KBManager extends Actor implements TrackingConsumer, DistanceDataCo
      */
     private final String cameraKbRulesFilePath;
 
+    /**
+     * Путь к файлу, в который необходимо записать детектированные атомарные знания, или пустая строка.
+     */
+    private final String atomicKnowledgeFilePath;
+
     /**
      * Максимальная длительность действия в секундах, по достижению которой будет отправлено сообщение о завершении
      * действия.
@@ -288,10 +295,10 @@ public class KBManager extends Actor implements TrackingConsumer, DistanceDataCo
 
     public KBManager(String videoName, int videoId, String bootstrapServer, String username, String password,
             String kbStateTopicPrefix, String devBehDetectionsTopicPrefix, int kbHistorySec, int inferencePeriodSec,
-            int devBehIgnorePeriodSec, Future<Double> fpsFuture, int maxQueuedRequests, String kbWorkerJarPath,
+            int devBehIgnorePeriodSec, Future<VideoInfo> fpsFuture, int maxQueuedRequests, String kbWorkerJarPath,
             String kbWorkerMemory, String libjplJavaLibraryPath, String generalKbRulesFilePath,
-            String cameraKbRulesFilePath, int maxActionDurationSec, int maxChildSkeletonLengthMm,
-            Runnable pipelineStopper, MetricService metricService)
+            String cameraKbRulesFilePath, String atomicKnowledgeDirPath, int maxActionDurationSec,
+            int maxChildSkeletonLengthMm, Runnable pipelineStopper, MetricService metricService)
     {
         this.managerName = "KBManager-" + videoName;
         this.bootstrapServer = bootstrapServer;
@@ -309,6 +316,8 @@ public class KBManager extends Actor implements TrackingConsumer, DistanceDataCo
         this.libjplJavaLibraryPath = libjplJavaLibraryPath;
         this.generalKbRulesFilePath = generalKbRulesFilePath;
         this.cameraKbRulesFilePath = Utils.isEmpty(cameraKbRulesFilePath) ? "" : cameraKbRulesFilePath;
+        this.atomicKnowledgeFilePath = atomicKnowledgeDirPath == null || atomicKnowledgeDirPath.trim().isEmpty() ? "" :
+                new File(atomicKnowledgeDirPath, videoName + ".pl").getAbsolutePath();
         this.maxActionDurationSec = maxActionDurationSec;
         this.maxChildSkeletonLengthMm = maxChildSkeletonLengthMm;
         this.pipelineStopper = pipelineStopper;
@@ -375,10 +384,10 @@ public class KBManager extends Actor implements TrackingConsumer, DistanceDataCo
     @Override
     protected void doFirst()
     {
-        double fps;
+        VideoInfo videoInfo;
         try
         {
-            fps = fpsFuture.get();
+            videoInfo = fpsFuture.get();
         }
         catch (Exception e)
         {
@@ -390,12 +399,12 @@ public class KBManager extends Actor implements TrackingConsumer, DistanceDataCo
             return;
         }
 
-        kbHistoryFrames = (int) (fps * kbHistorySec);
-        inferencePeriodFrames = (int) (fps * inferencePeriodSec);
-        devBehIgnorePeriodFrames = (int) (fps * devBehIgnorePeriodSec);
-        maxActionDurationFrames = (int) (fps * maxActionDurationSec);
+        kbHistoryFrames = (int) (videoInfo.fps * kbHistorySec);
+        inferencePeriodFrames = (int) (videoInfo.fps * inferencePeriodSec);
+        devBehIgnorePeriodFrames = (int) (videoInfo.fps * devBehIgnorePeriodSec);
+        maxActionDurationFrames = (int) (videoInfo.fps * maxActionDurationSec);
 
-        initKb(fps);
+        initKb(videoInfo.frameHeight, videoInfo.frameWidth, videoInfo.fps);
         loadKbHistory();
 
         if (getDoStop())
@@ -924,13 +933,14 @@ public class KBManager extends Actor implements TrackingConsumer, DistanceDataCo
     /**
      * Записывает в базу знаний статические правила, в частности, описания интересующих сцен девиантного поведения.
      */
-    private void initKb(double fps)
+    private void initKb(int frameHeight, int frameWidth, double fps)
     {
         // -Djava.library.path=/usr/lib/swi-prolog/lib/x86_64-linux
         ProcessBuilder builder = new ProcessBuilder("java", "-Xmx" + kbWorkerMemory, "-Xms" + kbWorkerMemory,
                 "-Djava.library.path=" + libjplJavaLibraryPath, "-jar", kbWorkerJarPath, generalKbRulesFilePath,
                 cameraKbRulesFilePath, Integer.toString(kbHistoryFrames), Integer.toString(devBehIgnorePeriodFrames),
-                Double.toString(fps));
+                Integer.toString(frameHeight), Integer.toString(frameWidth), Double.toString(fps),
+                atomicKnowledgeFilePath);
         try
         {
             kbWorkerProcess = builder.start();
@@ -1014,6 +1024,12 @@ public class KBManager extends Actor implements TrackingConsumer, DistanceDataCo
      */
     private void handleKbWorkerError(String errorMsg, Exception e) throws RuntimeException
     {
+        long startTimeMs = System.currentTimeMillis();
+        while (kbWorkerProcess.isAlive() && System.currentTimeMillis() < startTimeMs + 5000)
+        {
+            sleep(100);
+        }
+
         String workerError = null;
         if (!kbWorkerProcess.isAlive())
         {
diff --git a/dbm-service/src/main/java/com/devbeh/managers/PerceptionVisualizationManager.java b/dbm-service/src/main/java/com/devbeh/managers/PerceptionVisualizationManager.java
index 48999af93faac0cac3e43e23fc063de087b8bf87..ee878b197080876525bcda9f0172db678f8c71b3 100644
--- a/dbm-service/src/main/java/com/devbeh/managers/PerceptionVisualizationManager.java
+++ b/dbm-service/src/main/java/com/devbeh/managers/PerceptionVisualizationManager.java
@@ -13,6 +13,7 @@ import com.devbeh.Actor;
 import com.devbeh.DetectionClass;
 import com.devbeh.FrameIdAndBytes;
 import com.devbeh.MetricService;
+import com.devbeh.VideoInfo;
 import com.devbeh.data.Action;
 import com.devbeh.data.DetectionEntryOrBuilder;
 import com.devbeh.data.DistanceEstimationEntry;
@@ -91,7 +92,7 @@ public class PerceptionVisualizationManager extends Actor implements FrameConsum
     /**
      * Предоставляет fps обрабатываемого видеопотока. Используется для создания результирующего видео.
      */
-    private final Future<Double> fpsFuture;
+    private final Future<VideoInfo> fpsFuture;
 
     /**
      * Используется для остановки конвейера обработки видео в случае критичной ошибки.
@@ -165,7 +166,7 @@ public class PerceptionVisualizationManager extends Actor implements FrameConsum
 
 
     public PerceptionVisualizationManager(String videoName, String resultVideoDirPath, long initialConsumedFrameId,
-            boolean enabled, int maxQueuedRequests, Future<Double> fpsFuture, Runnable pipelineStopper,
+            boolean enabled, int maxQueuedRequests, Future<VideoInfo> fpsFuture, Runnable pipelineStopper,
             MetricService metricService)
     {
         this.managerName = "PerceptionVisualizationManager-" + videoName;
@@ -317,7 +318,7 @@ public class PerceptionVisualizationManager extends Actor implements FrameConsum
                 frameRecorder = new FFmpegFrameRecorder(resultVideoFile, currentFrameInfo.frameMat.arrayWidth(),
                         currentFrameInfo.frameMat.arrayHeight());
                 frameRecorder.setFormat("mp4");
-                frameRecorder.setFrameRate(fpsFuture.get());
+                frameRecorder.setFrameRate(fpsFuture.get().fps);
                 frameRecorder.setVideoQuality(0);
                 frameRecorder.start();
             }
diff --git a/dbm-service/src/main/java/com/devbeh/managers/TrackingManager.java b/dbm-service/src/main/java/com/devbeh/managers/TrackingManager.java
index d21f5f48817337d3dd27d5f035965b6a979ac706..23d68e185402f5e11528ec2bf661cdb2dc21b830 100644
--- a/dbm-service/src/main/java/com/devbeh/managers/TrackingManager.java
+++ b/dbm-service/src/main/java/com/devbeh/managers/TrackingManager.java
@@ -22,6 +22,7 @@ import com.devbeh.Actor;
 import com.devbeh.FrameIdAndBytes;
 import com.devbeh.MetricService;
 import com.devbeh.ReducibleSemaphore;
+import com.devbeh.VideoInfo;
 import com.devbeh.data.DetectionEntry;
 import com.devbeh.data.PerceptionRequest;
 import com.devbeh.data.PerceptionResponse;
@@ -134,7 +135,7 @@ public class TrackingManager extends AbstractDistributor implements FrameConsume
      * Может вызываться только после инициализации начального запрашиваемого кадра, поэтому можно использовать в любом
      * месте {@link #postDoFirst(long)}.
      */
-    private final Future<Double> fpsFuture;
+    private final Future<VideoInfo> fpsFuture;
 
     /**
      * Максимальная длительность перекрытия объекта в кадрах. Задается во время инициализации на основе fps.
@@ -154,7 +155,7 @@ public class TrackingManager extends AbstractDistributor implements FrameConsume
 
     public TrackingManager(String videoName, int videoId, String bootstrapServer, String username, String password,
             String requestTopicName, String responseTopicPrefix, String tmStateTopicPrefix, int maxOccludedDurationSec,
-            Future<Double> fpsFuture, int maxQueuedRequests, int maxProcessingRequests, DistanceEstimationManager dem,
+            Future<VideoInfo> fpsFuture, int maxQueuedRequests, int maxProcessingRequests, DistanceEstimationManager dem,
             PoseEstimationManager pem, ActionsManager am, KBManager kbm, PerceptionVisualizationManager pvm,
             Runnable pipelineStopper, MetricService metricService)
     {
@@ -168,7 +169,7 @@ public class TrackingManager extends AbstractDistributor implements FrameConsume
 
     private TrackingManager(String videoName, int videoId, String bootstrapServer, String username, String password,
             String clientId, TopicPartition requestTopicPartition, TopicPartition responseTopicPartition,
-            String tmStateTopicPrefix, int maxOccludedDurationSec, Future<Double> fpsFuture,
+            String tmStateTopicPrefix, int maxOccludedDurationSec, Future<VideoInfo> fpsFuture,
             CompletableFuture<Long> initialFrameIdFuture, int maxQueuedRequests, int maxProcessingRequests,
             ReducibleSemaphore processingRequestsSem, DistanceEstimationManager dem, PoseEstimationManager pem,
             ActionsManager am, KBManager kbm, PerceptionVisualizationManager pvm, Runnable pipelineStopper,
@@ -243,7 +244,7 @@ public class TrackingManager extends AbstractDistributor implements FrameConsume
         double fps;
         try
         {
-            fps = fpsFuture.get();
+            fps = fpsFuture.get().fps;
         }
         catch (ExecutionException e)
         {
@@ -412,6 +413,7 @@ public class TrackingManager extends AbstractDistributor implements FrameConsume
                         lastFrameIdToGlobalTrackIds.remove(ti.lastFrameId);
                     }
                     ti.lastFrameId = frameId;
+                    ti.detectionId = detectionId;
                 }
                 lastFrameIdToGlobalTrackIds.computeIfAbsent(frameId, f -> new HashSet<>()).add(globalTrackId);
 
@@ -425,7 +427,7 @@ public class TrackingManager extends AbstractDistributor implements FrameConsume
                 while (lastFrameIdIterator.hasNext())
                 {
                     Map.Entry<Long, Set<Long>> e = lastFrameIdIterator.next();
-                    if (e.getKey() >= frameId - maxOccludedDurationFrames)
+                    if (frameId - e.getKey() <= maxOccludedDurationFrames)
                     {
                         break;
                     }
@@ -454,17 +456,28 @@ public class TrackingManager extends AbstractDistributor implements FrameConsume
             Set<Long> gIds = lastFrameIdToGlobalTrackIds.get(frameId);
             if (gIds != null)
             {
-                for (long globalTrackId : gIds)
+                Iterator<Long> globalTrackIdIter = gIds.iterator();
+                while (globalTrackIdIter.hasNext())
                 {
+                    long globalTrackId = globalTrackIdIter.next();
                     TrackInfo ti = globalTrackIdToTrackInfo.get(globalTrackId);
                     Long newTrackId = detectionIdToTrackId.get(ti.detectionId);
-                    if (newTrackId == null || ti.trackId == newTrackId)
+                    if (newTrackId == null)
+                    {
+                        // Удаляем трек, которому не нашлось эквивалента в новом наборе
+                        globalTrackIdIter.remove();
+                        globalTrackIdToTrackInfo.remove(globalTrackId);
+                        trackIdToGlobalTrackId.remove(ti.trackId);
+                        continue;
+                    }
+                    else if (ti.trackId == newTrackId)
                     {
                         // Теоретически, newTrackId может отсутствовать, если трекер вернет новый набор detection
                         // при запуске его с новой конфигурацией. Поэтому минимизируем возможную ошибку
                         continue;
                     }
                     trackIdToGlobalTrackId.remove(ti.trackId);
+                    // Может быть вытеснен трек, который относится к "будущему". Такой элемент будет обработан далее
                     trackIdToGlobalTrackId.put(newTrackId, globalTrackId);
                     ti.trackId = newTrackId;
 
@@ -472,6 +485,11 @@ public class TrackingManager extends AbstractDistributor implements FrameConsume
                     stateChange.addEntriesBuilder().setGlobalTrackId(globalTrackId).setTrackId(newTrackId)
                             .setDetectionId(ti.detectionId);
                 }
+
+                if (gIds.isEmpty())
+                {
+                    lastFrameIdToGlobalTrackIds.remove(frameId);
+                }
             }
         }
         stateChange.setGlobalTrackIdCounter(globalTrackIdCounter);
@@ -668,7 +686,7 @@ public class TrackingManager extends AbstractDistributor implements FrameConsume
         /**
          * Идентификатор объекта в рамках последнего кадра.
          */
-        private final long detectionId;
+        private long detectionId;
 
 
         public TrackInfo(long trackId, long lastFrameId, long detectionId)
@@ -677,5 +695,16 @@ public class TrackingManager extends AbstractDistributor implements FrameConsume
             this.lastFrameId = lastFrameId;
             this.detectionId = detectionId;
         }
+
+
+        @Override
+        public String toString()
+        {
+            return "TrackInfo{" +
+                    "trackId=" + trackId +
+                    ", lastFrameId=" + lastFrameId +
+                    ", detectionId=" + detectionId +
+                    '}';
+        }
     }
 }
diff --git a/dbm-service/src/main/java/com/devbeh/managers/VideoProvisionManager.java b/dbm-service/src/main/java/com/devbeh/managers/VideoProvisionManager.java
index 6998e3d1713a2d39a4886eab1529b126414757bc..66b043581c7602b83a699e18085d71103d842e70 100644
--- a/dbm-service/src/main/java/com/devbeh/managers/VideoProvisionManager.java
+++ b/dbm-service/src/main/java/com/devbeh/managers/VideoProvisionManager.java
@@ -8,6 +8,7 @@ import java.util.concurrent.atomic.AtomicLong;
 import com.devbeh.Actor;
 import com.devbeh.FrameIdAndBytes;
 import com.devbeh.MetricService;
+import com.devbeh.VideoInfo;
 import com.devbeh.videoproviders.VideoProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -44,7 +45,7 @@ public class VideoProvisionManager extends Actor
     /**
      * Должна быть инициализирована fps обрабатываемого видеопотока.
      */
-    private final CompletableFuture<Double> fpsFuture;
+    private final CompletableFuture<VideoInfo> fpsFuture;
 
     // Получатели кадров видеозаписи
     private final DetectionManager dm;
@@ -75,7 +76,7 @@ public class VideoProvisionManager extends Actor
 
 
     public VideoProvisionManager(String videoName, VideoProvider videoProvider, int maxFrameSizePixels,
-            CompletableFuture<Double> fpsFuture, DetectionManager dm, TrackingManager tm,
+            CompletableFuture<VideoInfo> fpsFuture, DetectionManager dm, TrackingManager tm,
             PoseEstimationManager pem, DistanceEstimationManager dem, PerceptionVisualizationManager pvm,
             Runnable pipelineStopper, MetricService metricService)
     {
@@ -110,7 +111,9 @@ public class VideoProvisionManager extends Actor
         {
             // Инициализируем videoProvider для получения fps даже если потребителям не требуются данные, при этом
             // провайдер может определить Long.MAX_VALUE
-            fpsFuture.complete(videoProvider.initFps());
+            videoProvider.initVideoInfo(maxFrameSizePixels);
+            fpsFuture.complete(new VideoInfo(videoProvider.getHeight(), videoProvider.getWidth(),
+                    videoProvider.getFps()));
 
             long lastConsumedByAllFrameId = Math.min(
                     Math.min(
@@ -120,7 +123,7 @@ public class VideoProvisionManager extends Actor
             long initialFrameId = lastConsumedByAllFrameId == Long.MAX_VALUE ? Long.MAX_VALUE :
                     lastConsumedByAllFrameId + 1;
 
-            videoProvider.initFrameParameters(initialFrameId, maxFrameSizePixels);
+            videoProvider.initInitialFrameId(initialFrameId);
 
             if (initialFrameId == Long.MAX_VALUE)
             {
diff --git a/dbm-service/src/main/java/com/devbeh/videoproviders/FileVideoProvider.java b/dbm-service/src/main/java/com/devbeh/videoproviders/FileVideoProvider.java
index 458d6edf7cf6c29ebed54611c4ddf5c5ef1f0feb..3d3f7474b85f1d75464293d43acdc4168ed64515 100644
--- a/dbm-service/src/main/java/com/devbeh/videoproviders/FileVideoProvider.java
+++ b/dbm-service/src/main/java/com/devbeh/videoproviders/FileVideoProvider.java
@@ -95,7 +95,7 @@ public class FileVideoProvider implements VideoProvider
 
 
     @Override
-    public double initFps() throws FrameGrabber.Exception
+    public void initVideoInfo(int maxFrameSizePixels) throws FrameGrabber.Exception
     {
         converterToMat = new OpenCVFrameConverter.ToMat();
         outputPointer = new BytePointer();
@@ -109,27 +109,27 @@ public class FileVideoProvider implements VideoProvider
         videoFrameIntervalMs = 1000.0 / fg.getFrameRate();
         frameIntervalMs = Math.max(1000.0 / maxFps, videoFrameIntervalMs);
 
-        return 1000 / frameIntervalMs;
-    }
-
-
-    @Override
-    public void initFrameParameters(long initialFrameId, int maxFrameSizePixels)
-    {
-        this.initialFrameId = initialFrameId;
         double frameScaleFactor = Math.sqrt((double) maxFrameSizePixels / (fg.getImageHeight() * fg.getImageWidth()));
         if (frameScaleFactor >= 1)
         {
             width = fg.getImageWidth();
             height = fg.getImageHeight();
-            alteredSize = null;
         }
         else
         {
             width = (int) (fg.getImageWidth() * frameScaleFactor);
             height = (int) (fg.getImageHeight() * frameScaleFactor);
-            alteredSize = new Size(width, height);
         }
+        // Для создания нового Mat в отдельной области памяти определяем данный объект даже при неизменности размера
+        // кадра
+        alteredSize = new Size(width, height);
+    }
+
+
+    @Override
+    public void initInitialFrameId(long initialFrameId)
+    {
+        this.initialFrameId = initialFrameId;
     }
 
 
@@ -147,6 +147,13 @@ public class FileVideoProvider implements VideoProvider
     }
 
 
+    @Override
+    public double getFps()
+    {
+        return 1000 / frameIntervalMs;
+    }
+
+
     @Override
     public Optional<FrameIdAndBytes> read(long timeoutMs) throws IOException
     {
diff --git a/dbm-service/src/main/java/com/devbeh/videoproviders/VideoProvider.java b/dbm-service/src/main/java/com/devbeh/videoproviders/VideoProvider.java
index f2c91b976f08978447a2c16a275926666d7da323..c1d094543c3dc7da096f5667dbf27e375c36e236 100644
--- a/dbm-service/src/main/java/com/devbeh/videoproviders/VideoProvider.java
+++ b/dbm-service/src/main/java/com/devbeh/videoproviders/VideoProvider.java
@@ -12,27 +12,26 @@ import com.devbeh.FrameIdAndBytes;
 public interface VideoProvider
 {
     /**
-     * Выполняет первый этап инициализации, в результате которого определяется fps.
-     * Далее должен быть выполнен второй этап инициализации посредством вызова {@link #initFrameParameters(long, int)}.
+     * Выполняет первый этап инициализации, в результате которого определяется параметры видеопотока - размер кадра и
+     * fps.
+     * Далее должен быть выполнен второй этап инициализации посредством вызова {@link #initInitialFrameId(long)}.
      *
+     * @param maxFrameSizePixels максимальный размер кадра видеозаписи, полученный как height * width, в случае
+     *                           превышения будет осуществляться ресайз
      * @throws Exception В случае критичной ошибки, которая приводит к невозможности запуска обработки видео. Ошибки,
      * которые могут иметь временный характер, будут обработаны в реализации провайдера и не будут выброшены наружу.
      * Такие ошибки могут привести только к временной недоступности кадров.
-     *
-     * @return количество кадров в секунду
      */
-    double initFps() throws Exception;
+    void initVideoInfo(int maxFrameSizePixels) throws Exception;
 
     /**
-     * Выполняет второй этап инициализации. Данный метод необходимо вызывать после {@link #initFps()}.
+     * Выполняет второй этап инициализации. Данный метод необходимо вызывать после {@link #initVideoInfo(int)}.
      *
      * @param initialFrameId идентификатор кадра, с которого ожидается видеозапись (включая),
      *                       или {@link Long#MAX_VALUE}, если от провайдера требуется лишь определить fps (кадры при
      *                       этом запрашиваться не будут)
-     * @param maxFrameSizePixels максимальный размер кадра видеозаписи, полученный как height * width, в случае
-     *                           превышения будет осуществляться ресайз
      */
-    void initFrameParameters(long initialFrameId, int maxFrameSizePixels);
+    void initInitialFrameId(long initialFrameId);
 
     /**
      * Возвращает высоту кадка.
@@ -48,6 +47,13 @@ public interface VideoProvider
      */
     int getHeight();
 
+    /**
+     * Возвращает количество кадров в секунду.
+     *
+     * @return количество кадров в секунду
+     */
+    double getFps();
+
     /**
      * Считывает кадр видеозаписи.
      * frameId ожидается последовательным, но по каким-либо причинам допускается скачек. Кроме того, начальный frameId
diff --git a/kb-worker/src/main/java/com/devbeh/KBWorkerStarter.java b/kb-worker/src/main/java/com/devbeh/KBWorkerStarter.java
index 6228253a65ca22f10743e4917d3c474998730104..a22ab5edd6f1dbb204599397aff57569e5c97fa5 100644
--- a/kb-worker/src/main/java/com/devbeh/KBWorkerStarter.java
+++ b/kb-worker/src/main/java/com/devbeh/KBWorkerStarter.java
@@ -3,9 +3,14 @@ package com.devbeh;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -49,7 +54,7 @@ public class KBWorkerStarter
     private static final OutputStream KB_OUT = new BufferedOutputStream(System.out);
 
     // Шаблоны создания термов
-    private static final Term OBJ_INFO_TERM = Term.textToTerm("timeBetween(?, ?, Time), bounds(?, box(TLx, TLy, BRx, BRy), Time)");
+    private static final Term OBJ_INFO_TERM = Term.textToTerm("timeBetween(?, ?, Time), correctedBounds(?, box(TLx, TLy, BRx, BRy), Time)");
     private static final Term BOUNDS_TERM = Term.textToTerm("bounds(?, box(?, ?, ?, ?), ?)");
     private static final Term POSITION_TERM = Term.textToTerm("position(?, point(?, ?, ?), ?)");
     private static final Term PERSON_TERM = Term.textToTerm("person(?, ?)");
@@ -94,6 +99,11 @@ public class KBWorkerStarter
      */
     private static long LAST_FRAME_ID = 0;
 
+    /**
+     * Используется для
+     */
+    private static PrintWriter ATOMIC_KNOWLEDGE_OUT = null;
+
 
     /**
      * Принимает:
@@ -125,9 +135,9 @@ public class KBWorkerStarter
      * @param args параметры kb-процесса
      * @throws RuntimeException исключение в случае критической ошибки
      */
-    private static void run(String[] args) throws RuntimeException
+    private static void run(String[] args) throws Exception
     {
-        if (args.length < 5)
+        if (args.length < 8)
         {
             throw new RuntimeException("Invalid arguments: " + Arrays.toString(args));
         }
@@ -138,9 +148,26 @@ public class KBWorkerStarter
         KB_HISTORY_FRAMES = Integer.parseInt(args[2]);
         KNOWLEDGE_WINDOW = new ArrayBlockingQueue<>(KB_HISTORY_FRAMES + 1);
         DEV_BEH_IGNORE_PERIOD_FRAMES = Integer.parseInt(args[3]);
-        double fps = Double.parseDouble(args[4]);
+        int frameHeight = Integer.parseInt(args[4]);
+        int frameWidth = Integer.parseInt(args[5]);
+        double fps = Double.parseDouble(args[6]);
         FRAME_INTERVAL_MS = (int) Math.round(1000 / fps);
 
+        if (!args[7].isEmpty())
+        {
+            File atomicKnowledgeFile = new File(args[7]);
+            if (!atomicKnowledgeFile.getParentFile().exists())
+            {
+                if (!atomicKnowledgeFile.getParentFile().mkdirs())
+                {
+                    throw new RuntimeException("Can't create directories for atomic knowledge file: " +
+                            atomicKnowledgeFile.getAbsolutePath());
+                }
+            }
+            ATOMIC_KNOWLEDGE_OUT = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
+                    new FileOutputStream(atomicKnowledgeFile))));
+        }
+
         runQuery(new Query("consult", new Term[] { new Atom(generalKbRulesFilePath) }),
                 "KB general rules consulting error");
         if (!cameraKbRulesFilePath.isEmpty())
@@ -148,8 +175,26 @@ public class KBWorkerStarter
             runQuery(new Query("consult", new Term[] { new Atom(cameraKbRulesFilePath) }),
                     "KB camera specific rules consulting error");
         }
-        runQuery(new Query(Term.textParamsToTerm("assert(timeStep(?))",
-                new Term[] {new org.jpl7.Integer(FRAME_INTERVAL_MS)})), "Time step insertion error");
+
+        addAtomicKnowledge(Term.textParamsToTerm("timeStep(?)",
+                new Term[] {new org.jpl7.Integer(FRAME_INTERVAL_MS)}));
+
+        addAtomicKnowledge(Term.textParamsToTerm("frameHeight(?)", new Term[] {new org.jpl7.Integer(frameHeight)}));
+        addAtomicKnowledge(Term.textParamsToTerm("frameWidth(?)", new Term[] {new org.jpl7.Integer(frameWidth)}));
+
+        // Записываем знания для исправления ошибки отсутствия процедуры
+        addAtomicKnowledge(Term.textToTerm("person(p, -1)"));
+        addAtomicKnowledge(Term.textToTerm("bounds(p, box(0, 0, 0, 0), -1)"));
+        addAtomicKnowledge(Term.textToTerm("position(p, point(0, 0, 0), -1)"));
+        addAtomicKnowledge(Term.textToTerm("vehicle(v, v, -1)"));
+        addAtomicKnowledge(Term.textToTerm("animal(a, a, -1)"));
+        addAtomicKnowledge(Term.textToTerm("bag(b, -1)"));
+        addAtomicKnowledge(Term.textToTerm("phone(ph, -1)"));
+        addAtomicKnowledge(Term.textToTerm("child(c, -1)"));
+        addAtomicKnowledge(Term.textToTerm("lookDirection(p, vector(0, 0, 0), -1)"));
+        addAtomicKnowledge(Term.textToTerm("volumetricPosition(v, [], -1)"));
+
+        flushAtomicKnowledge();
 
         // Родительский процесс ожидает сообщение после успешной инициализации
         writeResponse(KBServiceResponse.newBuilder().setEmpty(Empty.newBuilder().setEmpty(true)).build());
@@ -171,6 +216,35 @@ public class KBWorkerStarter
     }
 
 
+    /**
+     * Записывает атомарное знание в БЗ и файл.
+     *
+     * @param term терм, записываемый в БЗ и файл
+     */
+    private static void addAtomicKnowledge(Term term)
+    {
+        runQuery(new Query(new Compound("asserta", new Term[] {term})),
+                "Static knowledge insertion error (" + term.toString() + ")");
+        if (ATOMIC_KNOWLEDGE_OUT != null)
+        {
+            ATOMIC_KNOWLEDGE_OUT.print(term);
+            ATOMIC_KNOWLEDGE_OUT.println(".");
+        }
+    }
+
+
+    /**
+     * Отправляет буферизированные файлы в файл.
+     */
+    private static void flushAtomicKnowledge()
+    {
+        if (ATOMIC_KNOWLEDGE_OUT != null)
+        {
+            ATOMIC_KNOWLEDGE_OUT.flush();
+        }
+    }
+
+
     /**
      * Выполняет переданный запрос, вызывая {@link Query#hasSolution()}. Если метод возвращает false, выбрасывает
      * исключение.
@@ -256,8 +330,10 @@ public class KBWorkerStarter
         // Записываем знания в бз
         for (Term t : frameKnowledge)
         {
-            runQuery(new Query("asserta", new Term[] {t}), "KB knowledge asserta error");
+            addAtomicKnowledge(t);
         }
+        flushAtomicKnowledge();
+
         LAST_FRAME_ID = knowledge.getFrameId();
         KNOWLEDGE_WINDOW.add(new FrameKnowledge(knowledge.getFrameId(), frameKnowledge));
 
@@ -515,7 +591,8 @@ public class KBWorkerStarter
                     .setEndFrameId(finishFrameId)
                     .setInferenceInfo(""); // Пока оставляем данное поле пустым
 
-            Map<Long, List<DevBehFrameObject>> frameInfoMap = new HashMap<>();
+            // Внутренняя Map на случай повторения детектирования одного объекта в кадре
+            Map<Long, Map<Long, DevBehFrameObject>> frameInfoMap = new HashMap<>();
             for (Term obj : devBeh.args())
             {
                 for (Map<String, Term> devBehObjInfo : new Query(OBJ_INFO_TERM.putParams(
@@ -527,7 +604,8 @@ public class KBWorkerStarter
                     float bottomRightX = devBehObjInfo.get("BRx").floatValue();
                     float bottomRightY = devBehObjInfo.get("BRy").floatValue();
 
-                    frameInfoMap.computeIfAbsent(frameId, f -> new ArrayList<>()).add(
+                    frameInfoMap.computeIfAbsent(frameId, f -> new HashMap<>()).put(
+                            obj.longValue(),
                             DevBehFrameObject.newBuilder()
                                     .setId(obj.longValue())
                                     .setBox(KBBox.newBuilder()
@@ -543,7 +621,7 @@ public class KBWorkerStarter
 
             frameInfoMap.entrySet().stream().sorted(Map.Entry.comparingByKey())
                     .forEach(frameInfo -> devBehEntryBuilder.addFrameInfoBuilder().setFrameId(frameInfo.getKey())
-                            .addAllObjects(frameInfo.getValue()));
+                            .addAllObjects(frameInfo.getValue().values()));
         }
 
         // Отправляем результат детектирования