コード例 #1
0
        /// <summary>
        /// Creates a <see cref="SimpleMemory"/> instance that stores the image.
        /// </summary>
        /// <param name="image">The image to process.</param>
        /// <param name="contrastValue">The contrast difference value.</param>
        /// <returns>The instance of the created <see cref="SimpleMemory"/>.</returns>
        private SimpleMemory CreateSimpleMemory(Bitmap image, int contrastValue)
        {
            var pixelCount = image.Width * image.Height;
            var cellCount  =
                pixelCount +
                (pixelCount % MaxDegreeOfParallelism != 0 ? MaxDegreeOfParallelism : 0) +
                3;
            var memory = new SimpleMemory(cellCount);

            memory.WriteUInt32(ChangeContrast_ImageWidthIndex, (uint)image.Width);
            memory.WriteUInt32(ChangeContrast_ImageHeightIndex, (uint)image.Height);
            memory.WriteInt32(ChangeContrast_ContrastValueIndex, contrastValue);

            for (int x = 0; x < image.Height; x++)
            {
                for (int y = 0; y < image.Width; y++)
                {
                    var pixel = image.GetPixel(y, x);

                    // This leaves 1 byte unused in each memory cell, but that would make the whole logic a lot more
                    // complicated, so good enough for a sample; if we'd want to optimize memory usage, that would be
                    // needed.
                    memory.Write4Bytes(
                        x * image.Width + y + ChangeContrast_ImageStartIndex,
                        new[] { pixel.R, pixel.G, pixel.B });
                }
            }

            return(memory);
        }
コード例 #2
0
        /// <summary>
        /// Changes the contrast of an image.
        /// </summary>
        /// <param name="memory">The <see cref="SimpleMemory"/> object representing the accessible memory space.</param>
        public virtual void ChangeContrast(SimpleMemory memory)
        {
            var imageWidth    = (ushort)memory.ReadUInt32(ChangeContrast_ImageWidthIndex);
            var imageHeight   = (ushort)memory.ReadUInt32(ChangeContrast_ImageHeightIndex);
            int contrastValue = memory.ReadInt32(ChangeContrast_ContrastValueIndex);

            if (contrastValue > 100)
            {
                contrastValue = 100;
            }
            else if (contrastValue < -100)
            {
                contrastValue = -100;
            }

            contrastValue = (100 + contrastValue * Multiplier) / 100;

            var tasks = new Task <PixelProcessingTaskOutput> [MaxDegreeOfParallelism];

            // Since we only need to compute the loop condition's right side once, not on each loop execution, it's an
            // optimization to put it in a separate variable. This way it's indeed computed only once.
            var pixelCount = imageHeight * imageWidth;
            var stepCount  = pixelCount / MaxDegreeOfParallelism;

            if (pixelCount % MaxDegreeOfParallelism != 0)
            {
                // This will take care of the rest of the pixels. This is wasteful as on the last step not all Tasks
                // will work on something but it's a way to keep the number of Tasks constant.
                stepCount += 1;
            }

            for (int i = 0; i < stepCount; i++)
            {
                for (int t = 0; t < MaxDegreeOfParallelism; t++)
                {
                    var pixelBytes = memory.Read4Bytes(i * MaxDegreeOfParallelism + t + ChangeContrast_ImageStartIndex);

                    // Using an input class to also pass contrastValue because it's currently not supported to access
                    // variables from the parent scope from inside Tasks (you need to explicitly pass in all inputs).
                    // Using an output class to pass the pixel values back because returning an array from Tasks is not
                    // supported at the time either.
                    tasks[t] = Task.Factory.StartNew(
                        inputObject =>
                    {
                        var input = (PixelProcessingTaskInput)inputObject;

                        return(new PixelProcessingTaskOutput
                        {
                            R = ChangePixelValue(input.PixelBytes[0], input.ContrastValue),
                            G = ChangePixelValue(input.PixelBytes[1], input.ContrastValue),
                            B = ChangePixelValue(input.PixelBytes[2], input.ContrastValue)
                        });
                    },
                        new PixelProcessingTaskInput {
                        PixelBytes = pixelBytes, ContrastValue = contrastValue
                    });
                }

                Task.WhenAll(tasks).Wait();

                for (int t = 0; t < MaxDegreeOfParallelism; t++)
                {
                    // It's no problem that we write just 3 bytes to a 4-byte slot.
                    memory.Write4Bytes(
                        i * MaxDegreeOfParallelism + t + ChangeContrast_ImageStartIndex,
                        new[] { tasks[t].Result.R, tasks[t].Result.G, tasks[t].Result.B });
                }
            }
        }