private unsafe void ProcessPixelsByAction(Bitmap processedBitmap, PixelAction actionForRgbPixels) { BitmapData bitmapData = processedBitmap.LockBits( new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), ImageLockMode.ReadWrite, processedBitmap.PixelFormat); int bytesPerPixel = Bitmap.GetPixelFormatSize(processedBitmap.PixelFormat) / 8; int heightInPixels = bitmapData.Height; int widthInBytes = bitmapData.Width * bytesPerPixel; byte *ptrFirstPixel = (byte *)bitmapData.Scan0; /*Parallel.For(0, heightInPixels, y => * {*/ for (int y = 0; y < heightInPixels; y++) { byte *currentLine = ptrFirstPixel + (y * bitmapData.Stride); for (int x = 0; x < widthInBytes; x = x + bytesPerPixel) { int blue = currentLine[x]; int green = currentLine[x + 1]; int red = currentLine[x + 2]; actionForRgbPixels.Invoke(ref red, ref green, ref blue); currentLine[x] = (byte)blue; currentLine[x + 1] = (byte)green; currentLine[x + 2] = (byte)red; } } //}); processedBitmap.UnlockBits(bitmapData); }
public TIA(IReadyDevice cpu) { CPU = cpu; // create an array to call the proper delegate based on the current active pixel for (int horz = 0; horz < MAX_HORIZONTAL; horz++) { // add VSYNC for (int vert = 0; vert < 3; vert++) { pixelActions[horz, vert] = new PixelAction(VerticalSync); } // add VBLANK for (int vert = 3; vert < 40; vert++) { pixelActions[horz, vert] = new PixelAction(VerticalBlank); } for (int vert = 40; vert < 232; vert++) { // add HBLANK if (horz < END_OF_HBLANK) { pixelActions[horz, vert] = new PixelAction(HorizontalBlank); } // viewable area else { pixelActions[horz, vert] = new PixelAction(ViewableArea); } } // add OVERSCAN for (int vert = 232; vert < MAX_VERTICAL; vert++) { pixelActions[horz, vert] = new PixelAction(Overscan); } } }
/// <summary> /// Пересчитывает центральный пиксель региона /// </summary> /// <param name="action">Действие выполненной над пикселями региона перед пересчетом центрального пикселя</param> /// <param name="pixels">Массив пикселей, который были изменены в регионе перед пересчетом центрального пикселя</param> private void CalculateCenter(PixelAction action = PixelAction.none, Pixel[] pixels = null) { if (RegionPixels == null) { return; } // Извлекаем матрицу идентификаторов пикселей - в каждой строке находится идентификатор (координаты x и y пикселя) int[][] pixelIds = new int[RegionPixels.Count][]; for (int i = 0; i < RegionPixels.Count; i++) { pixelIds[i] = RegionPixels[i].Id; } if (action == PixelAction.none) { // Инициализация массива сумм расстояний DistanceSums = new List <double>(); for (int i = 0; i < RegionPixels.Count; i++) { DistanceSums.Add(0.0); } // Ищем суммы расстояний от каждой точки до каждой точки региона for (int i = 0; i < RegionPixels.Count; i++) { // Считаем сумму расстояний от точки i до всех остальных точек for (int j = 0; j < RegionPixels.Count; j++) { if (i != j) { // Прибавляем к сумме расстояние от пикселя i до пикселя j DistanceSums[i] += Math.Sqrt((pixelIds[i][0] - pixelIds[j][0]) * (pixelIds[i][0] - pixelIds[j][0]) + (pixelIds[i][1] - pixelIds[j][1]) * (pixelIds[i][1] - pixelIds[j][1])); } } } } else if (action == PixelAction.add) { if (pixels == null) { return; } // Добавляем новые элементы списка расстояний для новых пикселей и добавляем к уже существующим суммам новые расстояния int oldDistancesSumsCount = DistanceSums.Count; // Фиксируем количество пикселей, которые были в регионе до добавления for (int i = 0; i < pixels.Length; i++) { int oldDistancesIterator = 0; double sum = 0.0; for (int j = 0; j < RegionPixels.Count; j++) { double distance = Math.Sqrt((pixels[i].Id[0] - pixelIds[j][0]) * (pixels[i].Id[0] - pixelIds[j][0]) + (pixels[i].Id[1] - pixelIds[j][1]) * (pixels[i].Id[1] - pixelIds[j][1])); sum += distance; // Если текущий пиксель относится еще к старым пикселям региона if (oldDistancesIterator < oldDistancesSumsCount) { DistanceSums[j] += distance; } // Увеличиваем счетчик просмотренных пикселей oldDistancesIterator++; } DistanceSums.Add(sum); } } else if (action == PixelAction.remove) { // В случае удаления пикселей, они удалены из списка пикселей и из списка расстояний уже до текущего момента if (pixels == null) { return; } // Уменьшаем суммы расстояний оставшихся пикселей на величины расстояний до удаленных пикселей for (int i = 0; i < pixels.Length; i++) { for (int j = 0; j < RegionPixels.Count; j++) { DistanceSums[j] -= Math.Sqrt((pixels[i].Id[0] - pixelIds[j][0]) * (pixels[i].Id[0] - pixelIds[j][0]) + (pixels[i].Id[1] - pixelIds[j][1]) * (pixels[i].Id[1] - pixelIds[j][1])); } } } else { return; } // Определение центрального пикселя региона double minSum = DistanceSums.Min(); for (int i = 0; i < DistanceSums.Count; i++) { if (DistanceSums[i] == minSum) { SpacialSenterId = pixelIds[i]; break; } } }
/// <summary> /// Пересчитывает все параметры для региона на основе параметров пикселей региона /// </summary> /// <param name="action">Действие, которое было произведено над пикселями перед вызовом функции</param> /// <param name="pixels">Массив пикселей, над которыми было произведено действие</param> public void CalculateParameters(PixelAction action = PixelAction.none, Pixel[] pixels = null) { if (RegionPixels == null) { return; } // если в регионе не осталось пикселей, то параметры региона сбрасываются if (RegionPixels.Count == 0) { SpacialSenterId[0] = SpacialSenterId[1] = -1; Area = 0; for (int i = 0; i < AverageTextureFeature.Length; i++) { AverageTextureFeature[i] = 0; } for (int i = 0; i < AverageConditionalIntensityFeature.Length; i++) { AverageConditionalIntensityFeature[i] = 0; } return; } if (action == PixelAction.none) { // расчет центра региона CalculateCenter(); // расчет площади региона Area = RegionPixels.Count; // расчет среднего значения вектора текстурной характеристики для региона for (int i = 0; i < RegionPixels[0].TextureFeatures.Length; i++) { double sum = 0.0; for (int j = 0; j < RegionPixels.Count; j++) { sum += RegionPixels[j].TextureFeatures[i]; } TextureFeatureSums[i] = sum; AverageTextureFeature[i] = sum / RegionPixels.Count; } // расчет среднего значения вектора интенсивности, полученного после условной фильтрации, для региона for (int i = 0; i < RegionPixels[0].ConditionalIntensityFeatures.Length; i++) { double sum = 0.0; for (int j = 0; j < RegionPixels.Count; j++) { sum += RegionPixels[j].ConditionalIntensityFeatures[i]; } ConditionalIntensityFeatureSums[i] = sum; AverageConditionalIntensityFeature[i] = sum / RegionPixels.Count; } } else { if (pixels == null) { return; } // расчет центра региона CalculateCenter(action, pixels); // расчет площади региона Area = RegionPixels.Count; // расчет среднего значения вектора текстурной характеристики для региона if (action == PixelAction.add) { for (int i = 0; i < pixels.Length; i++) { for (int j = 0; j < RegionPixels[0].TextureFeatures.Length; j++) { TextureFeatureSums[j] += pixels[i].TextureFeatures[j]; } } for (int i = 0; i < RegionPixels[0].TextureFeatures.Length; i++) { AverageTextureFeature[i] = TextureFeatureSums[i] / RegionPixels.Count; } } if (action == PixelAction.remove) { for (int i = 0; i < pixels.Length; i++) { for (int j = 0; j < RegionPixels[0].TextureFeatures.Length; j++) { TextureFeatureSums[j] -= pixels[i].TextureFeatures[j]; } } for (int i = 0; i < RegionPixels[0].TextureFeatures.Length; i++) { AverageTextureFeature[i] = TextureFeatureSums[i] / RegionPixels.Count; } } // расчет среднего значения вектора интенсивности, полученного после условной фильтрации, для региона if (action == PixelAction.add) { for (int i = 0; i < pixels.Length; i++) { for (int j = 0; j < RegionPixels[0].ConditionalIntensityFeatures.Length; j++) { ConditionalIntensityFeatureSums[j] += pixels[i].ConditionalIntensityFeatures[j]; } } for (int i = 0; i < RegionPixels[0].ConditionalIntensityFeatures.Length; i++) { AverageConditionalIntensityFeature[i] = ConditionalIntensityFeatureSums[i] / RegionPixels.Count; } } if (action == PixelAction.remove) { for (int i = 0; i < pixels.Length; i++) { for (int j = 0; j < RegionPixels[0].ConditionalIntensityFeatures.Length; j++) { ConditionalIntensityFeatureSums[j] -= pixels[i].ConditionalIntensityFeatures[j]; } } for (int i = 0; i < RegionPixels[0].ConditionalIntensityFeatures.Length; i++) { AverageConditionalIntensityFeature[i] = ConditionalIntensityFeatureSums[i] / RegionPixels.Count; } } } }
public static void ReadBC3AlphaBlock(long block, ref PixelColor[,] cache, int posX, PixelAction writeOut) { int alpha0 = (int)(block & 0xFF); int alpha1 = (int)((block >> 8) & 0xFF); bool isFirstGreater = alpha0 > alpha1; block = block >> 16; float[] alphaLookup = new float[8]; for (int j = 0; j < 8; j++) { alphaLookup[j] = BC3GradientInterpolate(j, alpha0, alpha1, isFirstGreater) / 255f; } int i = 0; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { int alphaIndex = (int)(block >> (i * 3)) & 0x7; float alpha = alphaLookup[alphaIndex]; i++; //cache[y, posX + x].a = alpha; writeOut(ref cache[y, posX + x], alpha); } } }
/// <summary> /// Пересчитывает центральный пиксель региона /// </summary> /// <param name="action">Действие выполненной над пикселями региона перед пересчетом центрального пикселя</param> /// <param name="pixels">Массив пикселей, который были изменены в регионе перед пересчетом центрального пикселя</param> private void CalculateCenter(PixelAction action = PixelAction.none, Pixel[] pixels = null) { if (RegionPixels == null) return; // Извлекаем матрицу идентификаторов пикселей - в каждой строке находится идентификатор (координаты x и y пикселя) int[][] pixelIds = new int[RegionPixels.Count][]; for (int i = 0; i < RegionPixels.Count; i++) pixelIds[i] = RegionPixels[i].Id; if (action == PixelAction.none) { // Инициализация массива сумм расстояний DistanceSums = new List<double>(); for (int i = 0; i < RegionPixels.Count; i++) DistanceSums.Add(0.0); // Ищем суммы расстояний от каждой точки до каждой точки региона for (int i = 0; i < RegionPixels.Count; i++) { // Считаем сумму расстояний от точки i до всех остальных точек for (int j = 0; j < RegionPixels.Count; j++) { if (i != j) { // Прибавляем к сумме расстояние от пикселя i до пикселя j DistanceSums[i] += Math.Sqrt((pixelIds[i][0] - pixelIds[j][0]) * (pixelIds[i][0] - pixelIds[j][0]) + (pixelIds[i][1] - pixelIds[j][1]) * (pixelIds[i][1] - pixelIds[j][1])); } } } } else if (action == PixelAction.add) { if (pixels == null) return; // Добавляем новые элементы списка расстояний для новых пикселей и добавляем к уже существующим суммам новые расстояния int oldDistancesSumsCount = DistanceSums.Count; // Фиксируем количество пикселей, которые были в регионе до добавления for (int i = 0; i < pixels.Length; i++) { int oldDistancesIterator = 0; double sum = 0.0; for (int j = 0; j < RegionPixels.Count; j++) { double distance = Math.Sqrt((pixels[i].Id[0] - pixelIds[j][0]) * (pixels[i].Id[0] - pixelIds[j][0]) + (pixels[i].Id[1] - pixelIds[j][1]) * (pixels[i].Id[1] - pixelIds[j][1])); sum += distance; // Если текущий пиксель относится еще к старым пикселям региона if (oldDistancesIterator < oldDistancesSumsCount) DistanceSums[j] += distance; // Увеличиваем счетчик просмотренных пикселей oldDistancesIterator++; } DistanceSums.Add(sum); } } else if (action == PixelAction.remove) { // В случае удаления пикселей, они удалены из списка пикселей и из списка расстояний уже до текущего момента if (pixels == null) return; // Уменьшаем суммы расстояний оставшихся пикселей на величины расстояний до удаленных пикселей for (int i = 0; i < pixels.Length; i++) for (int j = 0; j < RegionPixels.Count; j++) DistanceSums[j] -= Math.Sqrt((pixels[i].Id[0] - pixelIds[j][0]) * (pixels[i].Id[0] - pixelIds[j][0]) + (pixels[i].Id[1] - pixelIds[j][1]) * (pixels[i].Id[1] - pixelIds[j][1])); } else return; // Определение центрального пикселя региона double minSum = DistanceSums.Min(); for (int i = 0; i < DistanceSums.Count; i++) { if (DistanceSums[i] == minSum) { SpacialSenterId = pixelIds[i]; break; } } }
/// <summary> /// Пересчитывает все параметры для региона на основе параметров пикселей региона /// </summary> /// <param name="action">Действие, которое было произведено над пикселями перед вызовом функции</param> /// <param name="pixels">Массив пикселей, над которыми было произведено действие</param> public void CalculateParameters(PixelAction action = PixelAction.none, Pixel[] pixels = null) { if (RegionPixels == null) return; // если в регионе не осталось пикселей, то параметры региона сбрасываются if (RegionPixels.Count == 0) { SpacialSenterId[0] = SpacialSenterId[1] = -1; Area = 0; for (int i = 0; i < AverageTextureFeature.Length; i++) AverageTextureFeature[i] = 0; for (int i = 0; i < AverageConditionalIntensityFeature.Length; i++) AverageConditionalIntensityFeature[i] = 0; return; } if (action == PixelAction.none) { // расчет центра региона CalculateCenter(); // расчет площади региона Area = RegionPixels.Count; // расчет среднего значения вектора текстурной характеристики для региона for (int i = 0; i < RegionPixels[0].TextureFeatures.Length; i++) { double sum = 0.0; for (int j = 0; j < RegionPixels.Count; j++) sum += RegionPixels[j].TextureFeatures[i]; TextureFeatureSums[i] = sum; AverageTextureFeature[i] = sum / RegionPixels.Count; } // расчет среднего значения вектора интенсивности, полученного после условной фильтрации, для региона for (int i = 0; i < RegionPixels[0].ConditionalIntensityFeatures.Length; i++) { double sum = 0.0; for (int j = 0; j < RegionPixels.Count; j++) sum += RegionPixels[j].ConditionalIntensityFeatures[i]; ConditionalIntensityFeatureSums[i] = sum; AverageConditionalIntensityFeature[i] = sum / RegionPixels.Count; } } else { if (pixels == null) return; // расчет центра региона CalculateCenter(action, pixels); // расчет площади региона Area = RegionPixels.Count; // расчет среднего значения вектора текстурной характеристики для региона if (action == PixelAction.add) { for (int i = 0; i < pixels.Length; i++) for (int j = 0; j < RegionPixels[0].TextureFeatures.Length; j++) TextureFeatureSums[j] += pixels[i].TextureFeatures[j]; for (int i = 0; i < RegionPixels[0].TextureFeatures.Length; i++) AverageTextureFeature[i] = TextureFeatureSums[i] / RegionPixels.Count; } if (action == PixelAction.remove) { for (int i = 0; i < pixels.Length; i++) for (int j = 0; j < RegionPixels[0].TextureFeatures.Length; j++) TextureFeatureSums[j] -= pixels[i].TextureFeatures[j]; for (int i = 0; i < RegionPixels[0].TextureFeatures.Length; i++) AverageTextureFeature[i] = TextureFeatureSums[i] / RegionPixels.Count; } // расчет среднего значения вектора интенсивности, полученного после условной фильтрации, для региона if (action == PixelAction.add) { for (int i = 0; i < pixels.Length; i++) for (int j = 0; j < RegionPixels[0].ConditionalIntensityFeatures.Length; j++) ConditionalIntensityFeatureSums[j] += pixels[i].ConditionalIntensityFeatures[j]; for (int i = 0; i < RegionPixels[0].ConditionalIntensityFeatures.Length; i++) AverageConditionalIntensityFeature[i] = ConditionalIntensityFeatureSums[i] / RegionPixels.Count; } if (action == PixelAction.remove) { for (int i = 0; i < pixels.Length; i++) for (int j = 0; j < RegionPixels[0].ConditionalIntensityFeatures.Length; j++) ConditionalIntensityFeatureSums[j] -= pixels[i].ConditionalIntensityFeatures[j]; for (int i = 0; i < RegionPixels[0].ConditionalIntensityFeatures.Length; i++) AverageConditionalIntensityFeature[i] = ConditionalIntensityFeatureSums[i] / RegionPixels.Count; } } }