using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Threading; using System.Drawing.Imaging; namespace OldStarsFinder { public partial class Form1 : Form { //The number of processors or cores available in the computer for this application private int priProcessorCount = Environment.ProcessorCount; //The bitmaps list private List<Bitmap> prloBitmapList; //The long list with the old stars count private List<long> prliOldStarsCount; //The threads list private List<Thread> prloThreadList; //The original huge infrared bitmap portrait Bitmap proOriginalBitmap; public Form1() { InitializeComponent(); } public bool IsOldStar(Color poPixelColor) { //Hue between 150 and 258 //Saturation more than 0.10 //Brightness more than 0.90 return ((poPixelColor.GetHue() >= 150 && (poPixelColor.GetHue() <= 258)) && (poPixelColor.GetSaturation() >= 0.10) && (poPixelColor.GetBrightness() >= 0.90)); } private Bitmap CropBitmap(Bitmap proBitmap, Rectangle proRectangle) { //Create a new bitmap copying the portion of the original defined by proRectangle and keeping the PixelFormat var loCroppedBitmap = proBitmap.Clone(proRectangle, proBitmap.PixelFormat); //Return the cropped bitmap return loCroppedBitmap; } private void ThreadOldStarsFinder(object poThreadParameter) { //Retrieve the thread number reeived in object poThreadParameter int liThreadNumber = (int) poThreadParameter; //The pixel matrix (bitmap) row number (Y) int liRow; //The pixel matrix (bitmap col number (X) int liCol; //The pixel color Color loPixelColor; //Get my bitmap part from the bitmap list Bitmap loBitmap = prloBitmapList[liThreadNumber]; //Reset my old stars counter prliOldStarsCount[liThreadNumber] = 0; //Iterate through each pixel matrix (bitmap) row for (liRow = 0; liRow < loBitmap.Height; liRow++) { //Iterate through each pixel matrix (bitmap) cols for(liCol = 0; liCol < loBitmap.Width; liCol++) { //Get the pixel color for liCol and liRow loPixelColor = loBitmap.GetPixel(liCol, liRow); //Get the pixel color for liCol and liRow if (IsOldStar(loPixelColor)) { //The color range correspons to an old star //Change its color to a pure blue loBitmap.SetPixel(liCol, liRow, Color.Blue); //Increase the old stars counter prliOldStarsCount[liThreadNumber]++; } else { loBitmap.SetPixel(liCol, liRow, Color.FromArgb(128, loPixelColor)); } } } //Simulate heavy processing Random rnd = new Random(); Thread.Sleep(rnd.Next(2000, 2500)); } private void WaitForThreadsToDie() { //A bool flag bool lbContinue = true; int liDeadThreads = 0; int liThreadNumber; while (lbContinue) { for(liThreadNumber = 0; liThreadNumber < priProcessorCount; liThreadNumber++) { if (prloThreadList[liThreadNumber].IsAlive) { //One of the threads is still alive //exit the for loop and sleep 100 milliseconds break; } else { //Increase the dead threads count liDeadThreads++; progressBar1.Value = (int) ((liDeadThreads * 1.0 / priProcessorCount * 1.0) * 100.0); } } if (liDeadThreads == priProcessorCount) { //All the threads are dead, exit the while loop break; } Thread.Sleep(100); liDeadThreads = 0; } } private void ShowBitmapWithOldStars() { int liThreadNumber; //Each bitmap portion Bitmap loBitmap; //The starting row in each iteration int liStartRow = 0; //Calculate each bitmap's height int liEachBitmapHeight = ((int) (proOriginalBitmap.Height / priProcessorCount)) + 1; //Create a new bitmap with the whole width and height loBitmap = new Bitmap(proOriginalBitmap.Width, proOriginalBitmap.Height); Graphics g = Graphics.FromImage((Image) loBitmap); g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; for (liThreadNumber = 0; liThreadNumber < priProcessorCount; liThreadNumber++) { //Draw each portion in its corresponding absolute starting row g.DrawImage(prloBitmapList[liThreadNumber], 0, liStartRow); //Increase the starting row liStartRow += liEachBitmapHeight; } //Show the bitmap in the PictureBox picStarsBitmap picStarsBitmap.Image = loBitmap; g.Dispose(); } private void butFindOldStars_Click(object sender, EventArgs e) { progressBar1.Visible = true; proOriginalBitmap = new Bitmap(pictureBox1.Image); //Thread number int liThreadNumber; //Create the thread list, the long list and the bitmap list prloThreadList = new List<Thread>(priProcessorCount); prliOldStarsCount = new List<long>(priProcessorCount); prloBitmapList = new List<Bitmap>(priProcessorCount); int liStartRow = 0; int liEachBitmapHeight = ((int) (proOriginalBitmap.Height / priProcessorCount)) + 1; int liHeightToAdd = proOriginalBitmap.Height; Bitmap loBitmap; //Initialize the threads for (liThreadNumber = 0; liThreadNumber < priProcessorCount; liThreadNumber++) { //Just to occupy the number prliOldStarsCount.Add(0); if (liEachBitmapHeight > liHeightToAdd) { //The last bitmap height perhaps is less than the other bitmap height liEachBitmapHeight = liHeightToAdd; } loBitmap = CropBitmap(proOriginalBitmap, new Rectangle(0, liStartRow, proOriginalBitmap.Width, liEachBitmapHeight)); liHeightToAdd -= liEachBitmapHeight; liStartRow += liEachBitmapHeight; prloBitmapList.Add(loBitmap); //Add the new thread, with a parameterized start (to allow parameters) prloThreadList.Add(new Thread(new ParameterizedThreadStart(ThreadOldStarsFinder))); } //Now, start the threads for (liThreadNumber = 0; liThreadNumber < priProcessorCount; liThreadNumber++) { prloThreadList[liThreadNumber].Start(liThreadNumber); } WaitForThreadsToDie(); ShowBitmapWithOldStars(); progressBar1.Visible = false; } } }The code is available as a Windows Forms application in a Visual 2015 Solution available for download (zip) below:
Old Stars Finder (.zip) W5 image (NASA website): W5 image