Image Processing’de Dominant Rengin Bulunması
Selamlar;
Bugün image processing işlemlerinden en fazla kullanılan baskın rengi bulmaya çalışacağız. Kullanım yerleri sağlıkta renk körleri adına hastalık tespiti ve derecesi için yapılırken, trafikte ve basılı yayında dikkat çekicek işaretlerin populasyona göre renginin belirlenmesine, hatta reklamcılık sektöründe hangi renkte bannerların yani reklamların daha çok beyenildiğine dolayısı ile tıklandığına kadar gitmektedir. Hiçbir yaklaşımın %100 sonuç vermemesine karşın bana en yakın yöntemin üzerinde konuşacağız.
Öncelikle Image Upload yapıcağımız Index.cshtml’i aşağıdaki gibi Ajax Upload ile yazalım: Yükleme işleminden önce loader.gif gösterilmekte, işlem bittikten sonra da gizlenmektedir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@{ ViewBag.Title = "Home Page"; } <h2>Image Processing Dominant Rengin Bulunması</h2> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script> <script src="http://malsup.github.com/jquery.form.js"></script> <script> $('form').ajaxForm({ beforeSend:function(){ $('#loader').show(); }, success: function (url) { $('#loader').hide(); } }); </script> <img src="~/Content/loader.gif" id="loader" style="display:none" /> @using (Ajax.BeginForm("UploadImage", "Home", new AjaxOptions() { HttpMethod = "POST" }, new { encytype = "multipart/form-data" })) { @Html.AntiForgeryToken() <input type="file" name="files" /> <input type="submit" value="Resim Yükle" /> } <table><tr id="container"></tr></table> |
HomeController.cs: Aşağıda görüldüğü gibi ilgili resim Upload klasörüne ek yeni bir guid ismi ile kaydedilmektedir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
using ImageProcessing.Models; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Web; using System.Web.Mvc; namespace ImageProcessing.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } [HttpPost] [ValidateAntiForgeryToken] public string UploadImage(IEnumerable<HttpPostedFileBase> files) { if (files != null) { foreach (var file in files) { if (file != null && file.ContentLength > 0) { var routhPath = Server.MapPath("~/Upload"); string fileName = Path.GetFileNameWithoutExtension(file.FileName); fileName += "_" + Guid.NewGuid().ToString("N"); fileName += Path.GetExtension(file.FileName); var path = Path.Combine(routhPath, fileName); file.SaveAs(path); return "/Upload/" +fileName; } } } return ""; } } } |
Şimdi geldik Imagedeki dominant rengin bulunmasına.
PictureAnalysis.cs: Aşağıda görüldüğü gibi image, yatay ve aşağa doğru pixel pixel iç içe forlar ile taranıp ilgili herbir pixel, dictionary listesinde yok ise yeni atanıp var ise değeri bir arttırılmıştır. Daha sonra ençok kullanılan renk pixeli alınıp sınıfın static property’si olan MostDominantColor’a atanmıştır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
using System.Collections.Generic; using System.Linq; using System.Drawing; namespace ImageProcessing.Models { public static class PictureAnalysis { public static List<Color> TenDominantColors { get; private set; } public static List<int> TenDominantColorIncidences { get; private set; } public static Color MostDominantColor { get; private set; } public static int MostDominantColorRgb { get; private set; } private static int pixelColor; private static Dictionary<int, int> dctColorIncidence; public static void GetMostDominantColor(Bitmap theBitMap) { TenDominantColors = new List<Color>(); TenDominantColorIncidences = new List<int>(); MostDominantColor = Color.Empty; MostDominantColorRgb = 0; dctColorIncidence = new Dictionary<int, int>(); // bu kod daha da hızlandırılabilir. for (int row = 0; row < theBitMap.Size.Width; row++) { for (int col = 0; col < theBitMap.Size.Height; col++) { pixelColor = theBitMap.GetPixel(row, col).ToArgb(); if (dctColorIncidence.Keys.Contains(pixelColor)) { dctColorIncidence[pixelColor]++; } else { dctColorIncidence.Add(pixelColor, 1); } } } // .NET Generic Dictionary'nin sort işlemi %100 garanti değildir. Daha farklı sıralanabilir. var dctSortedByValueHighToLow = dctColorIncidence.OrderByDescending(x => x.Value).ToDictionary(x => x.Key, x => x.Value); // bu kısmı Linq kullanılarak yapılması daha sağlıklı olabilir. foreach (KeyValuePair<int, int> kvp in dctSortedByValueHighToLow.Take(10)) { TenDominantColors.Add(Color.FromArgb(kvp.Key)); TenDominantColorIncidences.Add(kvp.Value); } MostDominantColor = Color.FromArgb(dctSortedByValueHighToLow.First().Key); MostDominantColorRgb = dctSortedByValueHighToLow.First().Value; } } } |
Şimdi sıra geldi PictureAnalysis.cs class’ının UploadImage() methodunda kullanılmasına: Aşağıda görüldüğü gibi upload edilen image işlenerek ençok kullanılan renk belirlenir. Daha sonra ilgili renk pixel’ine ait ismi GetColorName() methodu ile alınır. Baskın renk bulunduktan sonra fileName’i “æ” semboli ile ayrılarak dominant rengin ismi client’a gönderilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public string UploadImage(IEnumerable<HttpPostedFileBase> files) { . . . Bitmap image = new Bitmap(path); PictureAnalysis.GetMostDominantColor(image); string colorName = GetColorName(PictureAnalysis.MostDominantColor); return "/Upload/" +fileName+"æ"+ colorName; } |
GetColorName(): Sisteme kayıtlı tüm renkler bir aşağıda görülen GetWebColors() ile çekildikten sonra ağırlıklı rengin Red, Green, Blue değerleri ile herbir çekilen sisteme ait rengin R, G, B değerleri farkı alınıp karesi ile temp değerine atılır. Bu temp değeri yani fark belirlediğimiz 500 değerinden küçük ise aradığımız rengi bulmuş oluruz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
public static String GetColorName(Color color) { WebColors = GetWebColors(); double dbl_input_red = Convert.ToDouble(color.R); double dbl_input_green = Convert.ToDouble(color.G); double dbl_input_blue = Convert.ToDouble(color.B); double dbl_test_red, dbl_test_green, dbl_test_blue, temp; double distance = 500.0; //Kabul edilecek fark Color nearest_color = Color.Empty; foreach (object o in WebColors) { if ((Color)o != Color.Transparent) { //İki Renk Arasında Öklid mesafesi bulunur. dbl_test_red = Math.Pow(Convert.ToDouble(((Color)o).R) - dbl_input_red, 2.0); dbl_test_green = Math.Pow(Convert.ToDouble (((Color)o).G) - dbl_input_green, 2.0); dbl_test_blue = Math.Pow(Convert.ToDouble (((Color)o).B) - dbl_input_blue, 2.0); temp = Math.Sqrt(dbl_test_blue + dbl_test_green + dbl_test_red); if (temp == 0.0) { nearest_color = (Color)o; break; } else if (temp < distance) { distance = temp; nearest_color = (Color)o; } } } return nearest_color.Name; } |
GetWebColors(): Reflection ile sisteme ait tüm renkler bir diziye atılır. Böylece yüklenen reklama ait baskın rengin, bu dizi içindeki renklerden hangisine en yakın olduğu bulunur.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private static System.Collections.ArrayList GetWebColors() { Type color = (typeof(Color)); System.Reflection.PropertyInfo[] propertyInfos = color.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); System.Collections.ArrayList colors = new System.Collections.ArrayList(); foreach (System.Reflection.PropertyInfo pi in propertyInfos) { if (pi.PropertyType.Equals(typeof(Color))) { Color c = (Color)pi.GetValue((object)(typeof(Color)), null); colors.Add(c); } } return colors; } |
Index.cshtml: Aşağıdaki $(‘form’).ajaxForm kısmında success: kısmına alttaki kod eklenerek ilgili <table><tr id=“container”> içine yeni bir <td> eklenmektedir. İlgili resmin dominant rengi, parametre olarak gelen “url” den ‘æ’ semboli ile ayrıldıktan sonra çevresi kırmızı bir <div> içine background rengi olarak adı ile birlikte gömülür. Daha sonra bu div yüklenen resimin üstüne konumlanır. Örnek çıktı yukarıda görüldüğü gibidir.
1 2 3 4 5 6 7 8 9 10 11 |
<script> $('form').ajaxForm({ beforeSend:function(){ $('#loader').show(); }, success: function (url) { $('#loader').hide(); $('#container').append('<td> <div style="background-color:' + url.split('æ')[1] + ';width:200px;border:4px solid red;padding:2px"><font color="white">' + url.split('æ')[1] + '</div><img id="theImg" src="' + url.split('æ')[0] + '" style="width:200px;height:200px"/></td>') } }); </script> |
Yukarıdaki örnekte de görüldüğü gibi yüklenen bir image’in ağırlıklı renginin bulunması aslında istatistiksel bir ortalamadır. Bu işlemde, image’in büyüklüğü ve renk paletindeki çeşitlilik, toplam harcanacak süre ve doğruluk üzerindeki etkisi malesef negatif yani ters orantılıdır. Birçok farklı alanda kullanılan digital imagelar, üzerlerinde yapılan processler ile bizi birçok dalda faydalı veriye ulaştıracağı red edilemez bir gerçektir.
Yeni bir makalede görüşmek üzere hoşçakalın.
Source Code: http://www.borakasmer.com/projects/ImageProcessing.rar
Kaynak: https://stackoverflow.com/questions/40885713/show-most-used-color-in-an-image
Guzel makale olmus Bora. Eline saglik.
Teşekkürler Yiğitcim.
İnşallah daha iyilerini yapıcam.
Hocam Selamlar;
Yine çok güzel ve özgün bir makale. Elinize sağlık.
Ankaradaki eventinize katılamadım ama mükemmel geçtiğini duydum. Saatlerce yazmışınız sonra direk hatasız çalışmış:)
İyi çalışmalar.
Hocam selamlar,
Sizden boyle degisik makaleler gormek guzel :)
Elinize saglik..
Teşekkürler Yiğit…
Hocam elinize sağlık. Aramada sizi görmek mutlu edici. Bu arada indirme linki iki url içeriyor :)