Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Predominant image colour expensive!



  • Hi All,

    Using QtQuick 2.5 // Qt 5.5.1

    I am trying to get the average colour from an image so i can display the colour in a container that is bigger than said image. This is working by loading in the source image to a Canvas then fetching the image data using getContext()-> getImageData

    However the loop for CanvasImageData->data object is time consuming and seems to lockup the application. Now i have tried to move this into a workscript however it seems that Worker Script will not accept the data's type (data : object).

    I could loop through the object to create an array but i feel this will also be time consuming and also make using Worker Script pointless. Before i pull my hair out i wanted to check i am not doing something stupid with parsing the data to the worker script!

    Was hoping for suggestions of things to try or a point in the right direction

    canvasPickedColour = "#ffffff" //Reset to force an onChanged signal.  This is to prevent opening and closing same synopsis and not getting a colour change signal not being received
    ctx = colourCanvas.getContext("2d");
    ctx.save();
    
    ctx.drawImage(imageSource, 0, 0, canvasWidth, canvasHeight);
    canvasImageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight)
    
    var rgb = { r:255 ,g:255 ,b:255 } // Set a base colour as a fallback for non-compliant browsers
    var count = 0
    var i = -4
    var data = canvasImageData.data;
    
    var length = data.length;
    //log.out("length: " + length)
    while ((i += searchQuality * 4) < length) {
    	count++;
    	rgb.r += data[i];
    	rgb.g += data[i+1];
    	rgb.b += data[i+2];
    }
    
    // floor the average values to give correct rgb values (ie: round number values)
    rgb.r = Math.floor(rgb.r/count);
    rgb.g = Math.floor(rgb.g/count);
    rgb.b = Math.floor(rgb.b/count);
    
    //Normalise the values from 0-255 to between 0 and 1..
    log.out("before normalize -> rgb.r: " + rgb.r + ", rgb.g: " + rgb.g + ", rgb.b: " + rgb.b)
    rgb.r = normalize(rgb.r, 0 , 255)
    rgb.g = normalize(rgb.g, 0 , 255)
    rgb.b = normalize(rgb.b, 0 , 255)
    log.out("after normalize -> rgb.r: " + rgb.r + ", rgb.g: " + rgb.g + ", rgb.b: " + rgb.b)
    
    
    var dominantColor = Qt.rgba(rgb.r, rgb.g, rgb.b)
    log.out("dominantColor: " + dominantColor)
    canvasPickedColour = dominantColor
    ctx.restore();
    
    function normalize(value, min, max) {
    	var normalized = (value - min) / (max - min);
    	return normalized;
    }
    

    Cheers,

    Rob.



  • @teh_raab said in Predominant image colour expensive!:

    However the loop for CanvasImageData->data object is time consuming and seems to lockup the application.

    Well how big is your canvasImageData.data.length? Big?! Because your loop is going to be busy throughout.



  • The length is 884736.

    My problem is that its locking up the GUI thread. I wanted to just take the data object returned from getImageData and parse it to a workscript for it to then loop through

    Also note that i have a "searchQuality" variable that i have set to 20 so actually we only process every 20th pixel. Going any higher than this will increase the risk of showing a less predominant colour.


  • Qt Champions 2018

    Do it in c++ and without Canvas, QtConcurrent will help you for making it asynchronous


Log in to reply