I'm trying to write a function in Scilab to display images.
I'm dealing with images as lists of matrices, and then converting the list to a hypermatrix inside the function. However, the code does not seem to work for images of the type uint16 or uint32.
This is the code I've been working on:
imshow()
function[] =imshow(Image)
global TYPE_DOUBLE; //retrieving list and creating 3 dimensional matrix out of it
dimensions=size(Image)
MaxUInt8 = 2 ^ 8 - 1;
MaxGrayValue = MaxUInt8; //changed from MaximumGrayValue
if dimensions==3 then
matSize=size(Image(1));
r=matrix(Image(1),matSize(1),matSize(2));
g=matrix(Image(2),matSize(1),matSize(2));
b=matrix(Image(3),matSize(1),matSize(2));
z(:,:,1)=uint8(r); //Since Matplot is not working with uint16 and uint32, convert every image to a
z(:,:,2)=uint8(g); //8 bit palette.
z(:,:,3)=uint8(b); //Note: this will affect the color depth.
[NumberOfRows NumberOfColumns NumberOfChannels] = size(z);
NumberOfPixels = NumberOfRows * NumberOfColumns;
Sample = z(1);
//printf("\nType of Sample: ");
//printf(typeof(Sample)); //DEBUG:
//printf("\n");
if type(Sample) == 1 then //type 1 = real/complex matrix of double
ColorMap = matrix(z, NumberOfPixels, NumberOfChannels);
disp(ColorMap);
else
TypeName = typeof(Sample)
select TypeName
case 'uint8'
MaxGrayValue = 2 ^ 8 - 1;
//printf("uint8\t%d", MaxGrayValue); //DEBUG:
case 'uint16'
MaxGrayValue = 2 ^ 16 - 1;
//ColorMap = double(matrix(z, NumberOfPixels, NumberOfChannels)) / MaxGrayValue;
//printf("uint16\t%d", MaxGrayValue); //DEBUG:
case 'uint32'
MaxGrayValue = 2 ^ 32 - 1;
//ColorMap = double(matrix(z, NumberOfPixels, NumberOfChannels)) / MaxGrayValue;
//printf("uint32\t%d", MaxGrayValue); //DEBUG:
end;
ColorMap = double(matrix(z, NumberOfPixels, NumberOfChannels)) / MaxGrayValue;
printf("\nCreated colormap with MaxGrayValue = %d\n", MaxGrayValue); //DEBUG:
end;
Img=z;
//Grayscale
elseif dimensions==1 then
matSize = size(Image(1));
Img=matrix(Image(1),matSize(1),matSize(2));
Img=Img';
select typeof(Img)
case 'uint8'
MaxGrayValue = MaxUInt8;
case 'uint16'
MaxGrayValue = max(Image(:)) ;
case 'uint32'
MaxGrayValue = max(Image(:));
end;
ColorMap = graycolormap(double(MaxGrayValue + 1)); //changed from MaximumGrayValue
end;
show(Img,ColorMap);
endfunction
show()
function[] =show(Img,ColorMap)
FigureHandle = gcf();
drawlater();
FigureHandle.color_map = ColorMap
FigureHandle.background = -2; // sets the background to white
FigureHandle.figure_name = "Title";
[NumberOfRows NumberOfColumns] = size(Img);
FigureHandle.axes_size = [NumberOfColumns NumberOfRows];
delete(gca()); // previous image is deleted
Diagram = gca();
[NumberOfRows NumberOfColumns] = size(Img);
Diagram.data_bounds = [1, 1; NumberOfColumns, NumberOfRows];
Diagram.axes_visible = ['off' 'off' 'off'];
Diagram.isoview = 'on';
Options = '082'; // Box is drawn around image.
//printf("\nGiven to Matplot: "); //DEBUG:
//printf(typeof(Img)); //DEBUG:
Matplot(Img, Options);
drawnow();
endfunction
The error I'm getting is:
!--error 202
Matplot: Wrong type for input argument #1: A real or integer expected.
at line 22 of function show called by :
at line 67 of function imshow called by :
imshow(a);
Any help would be great.
It seems that OpenCV and matplotlib all cannot support imshow of uint16 or uint32, so the images will be converted to uint8 when shown.
Related
I'm encountering a big problem when using the number 0 (zero) as a factor for the colors to generate scales, the numbers close to 0 (zero) end up becoming almost white, impossible to see a difference.
The idea is that above 0 (zero) it starts green and gets even stronger and below 0 (zero) starting with a red one and getting stronger.
I really need any number, even if it's 0.000001 already has a visible green and the -0.000001 has a visible red.
Link to SpreadSheet:
https://docs.google.com/spreadsheets/d/1uN5rDEeR10m3EFw29vM_nVXGMqhLcNilYrFOQfcC97s/edit?usp=sharing
Note to help with image translation and visualization:
Número = Number
Nenhum = None
Valor Máx. = Max Value
Valor Min. = Min Value
Current Result / Expected Result
After reading your new comments I understand that these are the requisites:
The values above zero should be green (with increased intensity the further beyond zero).
The values below zero should be red (with increased intensity the further beyond zero).
Values near zero should be coloured (not almost white).
Given those requisites, I developed an Apps Script project that would be useful in your scenario. This is the full project:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu("Extra").addItem("Generate gradient", "parseData").addToUi();
}
function parseData() {
var darkestGreen = "#009000";
var lighestGreen = "#B8F4B8";
var darkestRed = "#893F45";
var lighestRed = "#FEBFC4";
var range = SpreadsheetApp.getActiveRange();
var data = range.getValues();
var biggestPositive = Math.max.apply(null, data);
var biggestNegative = Math.min.apply(null, data);
var greenPalette = colourPalette(darkestGreen, lighestGreen, biggestPositive);
var redPalette = colourPalette(darkestRed, lighestRed, Math.abs(
biggestNegative) + 1);
var fullPalette = [];
for (var i = 0; i < data.length; i++) {
if (data[i] > 0) {
var cellColour = [];
cellColour[0] = greenPalette[data[i] - 1];
fullPalette.push(cellColour);
} else if (data[i] < 0) {
var cellColour = [];
cellColour[0] = redPalette[Math.abs(data[i]) - 1];
fullPalette.push(cellColour);
} else if (data[i] == 0) {
var cellColour = [];
cellColour[0] = null;
fullPalette.push(cellColour);
}
}
range.setBackgrounds(fullPalette);
}
function colourPalette(darkestColour, lightestColour, colourSteps) {
var firstColour = hexToRGB(darkestColour);
var lastColour = hexToRGB(lightestColour);
var blending = 0.0;
var gradientColours = [];
for (i = 0; i < colourSteps; i++) {
var colour = [];
blending += (1.0 / colourSteps);
colour[0] = firstColour[0] * blending + (1 - blending) * lastColour[0];
colour[1] = firstColour[1] * blending + (1 - blending) * lastColour[1];
colour[2] = firstColour[2] * blending + (1 - blending) * lastColour[2];
gradientColours.push(rgbToHex(colour));
}
return gradientColours;
}
function hexToRGB(hex) {
var colour = [];
colour[0] = parseInt((removeNumeralSymbol(hex)).substring(0, 2), 16);
colour[1] = parseInt((removeNumeralSymbol(hex)).substring(2, 4), 16);
colour[2] = parseInt((removeNumeralSymbol(hex)).substring(4, 6), 16);
return colour;
}
function removeNumeralSymbol(hex) {
return (hex.charAt(0) == '#') ? hex.substring(1, 7) : hex
}
function rgbToHex(rgb) {
return "#" + hex(rgb[0]) + hex(rgb[1]) + hex(rgb[2]);
}
function hex(c) {
var pool = "0123456789abcdef";
var integer = parseInt(c);
if (integer == 0 || isNaN(c)) {
return "00";
}
integer = Math.round(Math.min(Math.max(0, integer), 255));
return pool.charAt((integer - integer % 16) / 16) + pool.charAt(integer % 16);
}
First of all the script will use the Ui class to show a customised menu called Extra. That menu calls the main function parseData, that reads the whole selection data with getValues. That function holds the darkest/lightest green/red colours. I used some colours for my example, but I advise you to edit them as you wish. Based on those colours, the function colourPalette will use graphical linear interpolation between the two colours (lightest and darkest). That interpolation will return an array with colours from darkest to lightest, with as many in-betweens as the maximum integer in the column. Please notice how the function uses many minimal functions to run repetitive tasks (converting from hexadecimal to RGB, formatting, etc…). When the palette is ready, the main function will create an array with all the used colours (meaning that it will skip unused colours, to give sharp contrast between big and small numbers). Finally, it will apply the palette using the setBackgrounds method. Here you can see some sample results:
In that picture you can see one set of colours per column. Varying between random small and big numbers, numerical series and mixed small/big numbers. Please feel free to ask any doubt about this approach.
A very small improvement to acques-Guzel Heron
I made it skip all non numeric values, beforehand it just errored out.
I added an option in the menu to use a custom range.
Thank you very much acques-Guzel Heron
function onOpen() {
const ui = SpreadsheetApp.getUi();
ui.createMenu('Extra')
.addItem('Generate gradient', 'parseData')
.addItem('Custom Range', 'customRange')
.addToUi();
}
function parseData(customRange = null) {
const darkestGreen = '#009000';
const lighestGreen = '#B8F4B8';
const darkestRed = '#893F45';
const lighestRed = '#FEBFC4';
let range = SpreadsheetApp.getActiveRange();
if (customRange) {
range = SpreadsheetApp.getActiveSpreadsheet().getRange(customRange);
}
const data = range.getValues();
const biggestPositive = Math.max.apply(null, data.filter(a => !isNaN([a])));
const biggestNegative = Math.min.apply(null, data.filter(a => !isNaN([a])));
const greenPalette = colorPalette(darkestGreen, lighestGreen, biggestPositive);
const redPalette = colorPalette(darkestRed, lighestRed, Math.abs(biggestNegative) + 1);
const fullPalette = [];
for (const datum of data) {
if (datum > 0) {
fullPalette.push([greenPalette[datum - 1]]);
} else if (datum < 0) {
fullPalette.push([redPalette[Math.abs(datum) - 1]]);
} else if (datum == 0 || isNaN(datum)) {
fullPalette.push(['#ffffff']);
}
}
range.setBackgrounds(fullPalette);
}
function customRange() {
const ui = SpreadsheetApp.getUi();
result = ui.prompt("Please enter a range");
parseData(result.getResponseText());
}
function colorPalette(darkestColor, lightestColor, colorSteps) {
const firstColor = hexToRGB(darkestColor);
const lastColor = hexToRGB(lightestColor);
let blending = 0;
const gradientColors = [];
for (i = 0; i < colorSteps; i++) {
const color = [];
blending += (1 / colorSteps);
color[0] = firstColor[0] * blending + (1 - blending) * lastColor[0];
color[1] = firstColor[1] * blending + (1 - blending) * lastColor[1];
color[2] = firstColor[2] * blending + (1 - blending) * lastColor[2];
gradientColors.push(rgbToHex(color));
}
return gradientColors;
}
function hexToRGB(hex) {
const color = [];
color[0] = Number.parseInt((removeNumeralSymbol(hex)).slice(0, 2), 16);
color[1] = Number.parseInt((removeNumeralSymbol(hex)).slice(2, 4), 16);
color[2] = Number.parseInt((removeNumeralSymbol(hex)).slice(4, 6), 16);
return color;
}
function removeNumeralSymbol(hex) {
return (hex.charAt(0) == '#') ? hex.slice(1, 7) : hex;
}
function rgbToHex(rgb) {
return '#' + hex(rgb[0]) + hex(rgb[1]) + hex(rgb[2]);
}
function hex(c) {
const pool = '0123456789abcdef';
let integer = Number.parseInt(c, 10);
if (integer === 0 || isNaN(c)) {
return '00';
}
integer = Math.round(Math.min(Math.max(0, integer), 255));
return pool.charAt((integer - integer % 16) / 16) + pool.charAt(integer % 16);
}
I’m having troubles with gocv function Normalize. that in the documentation goes like that.
func Normalize(src Mat, dst *Mat, alpha float64, beta float64, typ NormType)
I’m calling this at my code and get a segmentation error in response. Can you help me fix this call?
package main
import (
“./imageprocessing”
“gocv.io/x/gocv”
// “fmt”
)
/** CovarFlags
// CovarScrambled indicates to scramble the results.
CovarScrambled CovarFlags = 0
// CovarNormal indicates to use normal covariation.
CovarNormal CovarFlags = 1
// CovarUseAvg indicates to use average covariation.
CovarUseAvg CovarFlags = 2
// CovarScale indicates to use scaled covariation.
CovarScale CovarFlags = 4
// CovarRows indicates to use covariation on rows.
CovarRows CovarFlags = 8
// CovarCols indicates to use covariation on columns.
CovarCols CovarFlags = 16
**/
func main() {
var size int
var normtype gocv.NormType = gocv.NormMinMax
size = imageprocessing.FolderLength("./imageprocessing/Images/danger")
Images := make([]gocv.Mat,size)
GLCMs := make([]gocv.Mat,size)
normalizedGLCMs := make([]gocv.Mat,size)
means := make([]gocv.Mat,size)
imageprocessing.ReadFolder(Images,"./imageprocessing/Images/danger",true,false,false)
//GroupGLCM(Images []gocv.Mat, GLCMs []gocv.Mat, means []gocv.Mat, show bool)
imageprocessing.GroupGLCM(Images, GLCMs, means, false)
//func Normalize(src Mat, dst *Mat, alpha float64, beta float64, typ NormType)
//min value of dst is alpha and max value of dst is beta
for i := 0; i < size; i++ {
gocv.Normalize(GLCMs[i], &normalizedGLCMs[i], 0.0, 255.0, normtype )
//imageprocessing.ShowImage("normalizedGLCMs", normalizedGLCMs[i], 100)
}
The following code runs without exception on iOS (Xcode-v6.2 and openCV-v3.0beta). But for some reason the image the function returns is "black" !
The code is adapted from this link ! I tried to replace the oldish "IplImage*" by more modern "cv::Mat" matrices. Does anybody know if my function still has a mistake or why it would return a completely "black" image instead of a colored image in HSV-format.
By the way, the reason I would want to use this function [instead of cvtColor(cv_src, imgHSV, cv::COLOR_BGR2HSV)] is that I would like to get 0-255 range of Hue-values's (...since OpenCV only allows Hues up to 180 instead of 255).
// Create a HSV image from the RGB image using the full 8-bits, since OpenCV only allows Hues up to 180 instead of 255.
cv::Mat convertImageRGBtoHSV(cv::Mat imageRGB) {
float fR, fG, fB;
float fH, fS, fV;
const float FLOAT_TO_BYTE = 255.0f;
const float BYTE_TO_FLOAT = 1.0f / FLOAT_TO_BYTE;
// Create a blank HSV image
cv::Mat imageHSV(imageRGB.rows, imageRGB.cols, CV_8UC3);
int rowSizeHSV = (int)imageHSV.step; // Size of row in bytes, including extra padding.
char *imHSV = (char*)imageHSV.data; // Pointer to the start of the image pixels.
if (imageRGB.depth() == 8 && imageRGB.channels() == 3) {
std::vector<cv::Mat> planes(3);
cv::split(imageRGB, planes);
cv::Mat R = planes[2];
cv::Mat G = planes[1];
cv::Mat B = planes[0];
for(int y = 0; y < imageRGB.rows; ++y)
{
// get pointers to each row
cv::Vec3b* row = imageRGB.ptr<cv::Vec3b>(y);
// now scan the row
for(int x = 0; x < imageRGB.cols; ++x)
{
// Get the RGB pixel components. NOTE that OpenCV stores RGB pixels in B,G,R order.
cv::Vec3b pixel = row[x];
int bR = pixel[2];
int bG = pixel[1];
int bB = pixel[0];
// Convert from 8-bit integers to floats.
fR = bR * BYTE_TO_FLOAT;
fG = bG * BYTE_TO_FLOAT;
fB = bB * BYTE_TO_FLOAT;
// Convert from RGB to HSV, using float ranges 0.0 to 1.0.
float fDelta;
float fMin, fMax;
int iMax;
// Get the min and max, but use integer comparisons for slight speedup.
if (bB < bG) {
if (bB < bR) {
fMin = fB;
if (bR > bG) {
iMax = bR;
fMax = fR;
}
else {
iMax = bG;
fMax = fG;
}
}
else {
fMin = fR;
fMax = fG;
iMax = bG;
}
}
else {
if (bG < bR) {
fMin = fG;
if (bB > bR) {
fMax = fB;
iMax = bB;
}
else {
fMax = fR;
iMax = bR;
}
}
else {
fMin = fR;
fMax = fB;
iMax = bB;
}
}
fDelta = fMax - fMin;
fV = fMax; // Value (Brightness).
if (iMax != 0) { // Make sure it's not pure black.
fS = fDelta / fMax; // Saturation.
float ANGLE_TO_UNIT = 1.0f / (6.0f * fDelta); // Make the Hues between 0.0 to 1.0 instead of 6.0
if (iMax == bR) { // between yellow and magenta.
fH = (fG - fB) * ANGLE_TO_UNIT;
}
else if (iMax == bG) { // between cyan and yellow.
fH = (2.0f/6.0f) + ( fB - fR ) * ANGLE_TO_UNIT;
}
else { // between magenta and cyan.
fH = (4.0f/6.0f) + ( fR - fG ) * ANGLE_TO_UNIT;
}
// Wrap outlier Hues around the circle.
if (fH < 0.0f)
fH += 1.0f;
if (fH >= 1.0f)
fH -= 1.0f;
}
else {
// color is pure Black.
fS = 0;
fH = 0; // undefined hue
}
// Convert from floats to 8-bit integers.
int bH = (int)(0.5f + fH * 255.0f);
int bS = (int)(0.5f + fS * 255.0f);
int bV = (int)(0.5f + fV * 255.0f);
// Clip the values to make sure it fits within the 8bits.
if (bH > 255)
bH = 255;
if (bH < 0)
bH = 0;
if (bS > 255)
bS = 255;
if (bS < 0)
bS = 0;
if (bV > 255)
bV = 255;
if (bV < 0)
bV = 0;
// Set the HSV pixel components.
uchar *pHSV = (uchar*)(imHSV + y*rowSizeHSV + x*3);
*(pHSV+0) = bH; // H component
*(pHSV+1) = bS; // S component
*(pHSV+2) = bV; // V component
}
}
}
return imageHSV;
}
The cv::Mat M.depth() of a CV_8UC3-type matrix does unfortunately not return 8 - but instead it returns 0
Please have a look at the file "type_c.h"
#define CV_8U 0
#define CV_CN_SHIFT 3
#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
depth() doesn't return the actual bit depth but the number symbol that represents the depth !!
After replacing to the following line - it all works !! (i.e. replacing .depth() by .type() in the if-statement...)
if (imageHSV.type() == CV_8UC3 && imageHSV.channels() == 3) {...}
Hi,
I am coding in OpenCL.
I am converting a "C function" having 2D array starting from i=1 and j=1 .PFB .
cv::Mat input; //Input :having some data in it ..
//Image input size is :input.rows=288 ,input.cols =640
cv::Mat output(input.rows-2,input.cols-2,CV_32F); //Output buffer
//Image output size is :output.rows=286 ,output.cols =638
This is a code Which I want to modify in OpenCL:
for(int i=1;i<output.rows-1;i++)
{
for(int j=1;j<output.cols-1;j++)
{
float xVal = input.at<uchar>(i-1,j-1)-input.at<uchar>(i-1,j+1)+ 2*(input.at<uchar>(i,j-1)-input.at<uchar>(i,j+1))+input.at<uchar>(i+1,j-1) - input.at<uchar>(i+1,j+1);
float yVal = input.at<uchar>(i-1,j-1) - input.at<uchar>(i+1,j-1)+ 2*(input.at<uchar>(i-1,j) - input.at<uchar>(i+1,j))+input.at<uchar>(i-1,j+1)-input.at<uchar>(i+1,j+1);
output.at<float>(i-1,j-1) = xVal*xVal+yVal*yVal;
}
}
...
Host code :
//Input Image size is :input.rows=288 ,input.cols =640
//Output Image size is :output.rows=286 ,output.cols =638
OclStr->global_work_size[0] =(input.cols);
OclStr->global_work_size[1] =(input.rows);
size_t outBufSize = (output.rows) * (output.cols) * 4;//4 as I am copying all 4 uchar values into one float variable space
cl_mem cl_input_buffer = clCreateBuffer(
OclStr->context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR ,
(input.rows) * (input.cols),
static_cast<void *>(input.data), &OclStr->returnstatus);
cl_mem cl_output_buffer = clCreateBuffer(
OclStr->context, CL_MEM_WRITE_ONLY| CL_MEM_USE_HOST_PTR ,
(output.rows) * (output.cols) * sizeof(float),
static_cast<void *>(output.data), &OclStr->returnstatus);
OclStr->returnstatus = clSetKernelArg(OclStr->objkernel, 0, sizeof(cl_mem), (void *)&cl_input_buffer);
OclStr->returnstatus = clSetKernelArg(OclStr->objkernel, 1, sizeof(cl_mem), (void *)&cl_output_buffer);
OclStr->returnstatus = clEnqueueNDRangeKernel(
OclStr->command_queue,
OclStr->objkernel,
2,
NULL,
OclStr->global_work_size,
NULL,
0,
NULL,
NULL
);
clEnqueueMapBuffer(OclStr->command_queue, cl_output_buffer, true, CL_MAP_READ, 0, outBufSize, 0, NULL, NULL, &OclStr->returnstatus);
kernel Code :
__kernel void Sobel_uchar (__global uchar *pSrc, __global float *pDstImage)
{
const uint cols = get_global_id(0)+1;
const uint rows = get_global_id(1)+1;
const uint width= get_global_size(0);
uchar Opsoble[8];
Opsoble[0] = pSrc[(cols-1)+((rows-1)*width)];
Opsoble[1] = pSrc[(cols+1)+((rows-1)*width)];
Opsoble[2] = pSrc[(cols-1)+((rows+0)*width)];
Opsoble[3] = pSrc[(cols+1)+((rows+0)*width)];
Opsoble[4] = pSrc[(cols-1)+((rows+1)*width)];
Opsoble[5] = pSrc[(cols+1)+((rows+1)*width)];
Opsoble[6] = pSrc[(cols+0)+((rows-1)*width)];
Opsoble[7] = pSrc[(cols+0)+((rows+1)*width)];
float gx = Opsoble[0]-Opsoble[1]+2*(Opsoble[2]-Opsoble[3])+Opsoble[4]-Opsoble[5];
float gy = Opsoble[0]-Opsoble[4]+2*(Opsoble[6]-Opsoble[7])+Opsoble[1]-Opsoble[5];
pDstImage[(cols-1)+(rows-1)*width] = gx*gx + gy*gy;
}
Here I am not able to get the output as expected.
I am having some questions that
My for loop is starting from i=1 instead of zero, then How can I get proper index by using the global_id() in x and y direction
What is going wrong in my above kernel code :(
I am suspecting there is a problem in buffer stride but not able to further break my head as already broke it throughout a day :(
I have observed that with below logic output is skipping one or two frames after some 7/8 frames sequence.
I have added the screen shot of my output which is compared with the reference output.
My above logic is doing partial sobelling on my input .I changed the width as -
const uint width = get_global_size(0)+1;
PFB
Your suggestions are most welcome !!!
It looks like you may be fetching values in (y,x) format in your opencl version. Also, you need to add 1 to the global id to replicate your for loops starting from 1 rather than 0.
I don't know why there is an unused iOffset variable. Maybe your bug is related to this? I removed it in my version.
Does this kernel work better for you?
__kernel void simple(__global uchar *pSrc, __global float *pDstImage)
{
const uint i = get_global_id(0) +1;
const uint j = get_global_id(1) +1;
const uint width = get_global_size(0) +2;
uchar Opsoble[8];
Opsoble[0] = pSrc[(i-1) + (j - 1)*width];
Opsoble[1] = pSrc[(i-1) + (j + 1)*width];
Opsoble[2] = pSrc[i + (j-1)*width];
Opsoble[3] = pSrc[i + (j+1)*width];
Opsoble[4] = pSrc[(i+1) + (j - 1)*width];
Opsoble[5] = pSrc[(i+1) + (j + 1)*width];
Opsoble[6] = pSrc[(i-1) + (j)*width];
Opsoble[7] = pSrc[(i+1) + (j)*width];
float gx = Opsoble[0]-Opsoble[1]+2*(Opsoble[2]-Opsoble[3])+Opsoble[4]-Opsoble[5];
float gy = Opsoble[0]-Opsoble[4]+2*(Opsoble[6]-Opsoble[7])+Opsoble[1]-Opsoble[5];
pDstImage[(i-1) + (j-1)*width] = gx*gx + gy*gy ;
}
I am a bit apprehensive about posting an answer suggesting optimizations to your kernel, seeing as the original output has not been reproduced exactly as of yet. There is a major improvement available to be made for problems related to image processing/filtering.
Using local memory will help you out by reducing the number of global reads by a factor of eight, as well as grouping the global writes together for potential gains with the single write-per-pixel output.
The kernel below reads a block of up to 34x34 from pSrc, and outputs a 32x32(max) area of the pDstImage. I hope the comments in the code are enough to guide you in using the kernel. I have not been able to give this a complete test, so there could be changes required. Any comments are appreciated as well.
__kernel void sobel_uchar_wlocal (__global uchar *pSrc, __global float *pDstImage, __global uint2 dimDstImage)
{
//call this kernel 1-dimensional work group size: 32x1
//calculates 32x32 region of output with 32 work items
const uint wid = get_local_id(0);
const uint wid_1 = wid+1; // corrected for the calculation step
const uint2 gid = (uint2)(get_group_id(0),get_group_id(1));
const uint localDim = get_local_size(0);
const uint2 globalTopLeft = (uint2)(localDim * gid.x, localDim * gid.y); //position in pSrc to copy from/to
//dimLocalBuff is used for the right and bottom edges of the image, where the work group may run over the border
const uint2 dimLocalBuff = (uint2)(localDim,localDim);
if(dimDstImage.x - globalTopLeft.x < dimLocalBuff.x){
dimLocalBuff.x = dimDstImage.x - globalTopLeft.x;
}
if(dimDstImage.y - globalTopLeft.y < dimLocalBuff.y){
dimLocalBuff.y = dimDstImage.y - globalTopLeft.y;
}
int i,j;
//save region of data into local memory
__local uchar srcBuff[34][34]; //34^2 uchar = 1156 bytes
for(j=-1;j<dimLocalBuff.y+1;j++){
for(i=x-1;i<dimLocalBuff.x+1;i+=localDim){
srcBuff[i+1][j+1] = pSrc[globalTopLeft.x+i][globalTopLeft.y+j];
}
}
mem_fence(CLK_LOCAL_MEM_FENCE);
//compute output and store locally
__local float dstBuff[32][32]; //32^2 float = 4096 bytes
if(wid_1 < dimLocalBuff.x){
for(i=0;i<dimLocalBuff.y;i++){
float gx = srcBuff[(wid_1-1)+ (i - 1)]-srcBuff[(wid_1-1)+ (i + 1)]+2*(srcBuff[wid_1+ (i-1)]-srcBuff[wid_1+ (i+1)])+srcBuff[(wid_1+1)+ (i - 1)]-srcBuff[(wid_1+1)+ (i + 1)];
float gy = srcBuff[(wid_1-1)+ (i - 1)]-srcBuff[(wid_1+1)+ (i - 1)]+2*(srcBuff[(wid_1-1)+ (i)]-srcBuff[(wid_1+1)+ (i)])+srcBuff[(wid_1-1)+ (i + 1)]-srcBuff[(wid_1+1)+ (i + 1)];
dstBuff[wid][i] = gx*gx + gy*gy;
}
}
mem_fence(CLK_LOCAL_MEM_FENCE);
//copy results to output
for(j=0;j<dimLocalBuff.y;j++){
for(i=0;i<dimLocalBuff.x;i+=localDim){
srcBuff[i][j] = pSrc[globalTopLeft.x+i][globalTopLeft.y+j];
}
}
}
i am new to this website, please let me know if i have made any mistake on my post.
I have some questions regarding calculating and drawing histogram in javacv. Below are the codes that i have written based on some information that i have searched:
There is this error that i get: OpenCV Error: One of arguments' values is out of range (index is out of range) in unknown function, file ......\src\opencv\modules\core\src\array.cpp, line 1691
private CvHistogram getHistogram(IplImage image) {//get histogram data, input has been converted to grayscale beforehand
IplImage[] hsvImage1 = {image};
//bins and value-range
int numberOfBins = 256;
float minRange = 0.0f;
float maxRange = 255.0f;
// Allocate histogram object
int dims = 1;
int[] sizes = new int[]{numberOfBins};
int histType = CV_HIST_ARRAY;
float[] minMax = new float[]{minRange, maxRange};
float[][] ranges = new float[][]{minMax};
CvHistogram hist = cvCreateHist(dims, sizes, histType, ranges, 1);
cvCalcHist(hsvImage1, hist, 0, null);
return hist;
}
private IplImage DrawHistogram(CvHistogram hist, IplImage image) {//draw histogram
int scaleX = 1;
int scaleY = 1;
int i;
float[] max_value = {0};
int[] int_value = {0};
cvGetMinMaxHistValue(hist, max_value, max_value, int_value, int_value);//get min and max value for histogram
IplImage imgHist = cvCreateImage(cvSize(256, image.height() ),IPL_DEPTH_8U,1);//create image to store histogram
cvZero(imgHist);
CvPoint pts = new CvPoint(5);
for (i = 0; i < 256; i++) {//draw the histogram
float value = opencv_legacy.cvQueryHistValue_1D(hist, i);
float nextValue = opencv_legacy.cvQueryHistValue_1D(hist, i + 1);
pts.position(0).x(i * scaleX).y(image.height() * scaleY);
pts.position(1).x(i * scaleX + scaleX).y(image.height() * scaleY);
pts.position(2).x(i * scaleX + scaleX).y((int)((image.height() - nextValue * image.height() /max_value[0]) * scaleY));
pts.position(3).x(i * scaleX).y((int)((image.height() - value * image.height() / max_value[0]) * scaleY));
pts.position(4).x(i * scaleX).y(image.height() * scaleY);
cvFillConvexPoly(imgHist, pts.position(0), 5, CvScalar.RED, CV_AA, 0);
}
return imgHist;
}
I have tried searching few links that i provided at the bottom, however, each of them are in different language, therefore i am not sure i have converted them to java correctly. To be honest there are few things i doubt, will be glad if any advice can be provided, such as:
float[] max_value = {0}; // i referred to the internet and it helps me to getby syntax error in cvGetMinMaxHistValue() , not sure if it will cause logic error
pts.position(3).x(i * scaleX).y((int)((image.height() - value * image.height() / max_value[0]) * scaleY)); // i put int to downcast it to the type the pts will recognise, and one more thing is max_value[0] is 0, wondering if it will cause logical error due to division
Links used:
//use this
public CvHistogram getHistogram(IplImage image) {//get histogram data, input has been converted to grayscale beforehand
IplImageArray hsvImage1 = splitChannels(image);
//bins and value-range
int numberOfBins = 256;
float minRange = 0.0f;
float maxRange = 255.0f;
// Allocate histogram object
int dims = 1;
int[] sizes = new int[]{numberOfBins};
int histType = CV_HIST_ARRAY;
float[] minMax = new float[]{minRange, maxRange};
float[][] ranges = new float[][]{minMax};
CvHistogram hist = cvCreateHist(dims, sizes, histType, ranges, 1);
cvCalcHist(hsvImage1, hist, 0, null);
return hist;
}
private IplImageArray splitChannels(IplImage hsvImage) {
CvSize size = hsvImage.cvSize();
int depth = hsvImage.depth();
IplImage channel0 = cvCreateImage(size, depth, 1);
IplImage channel1 = cvCreateImage(size, depth, 1);
IplImage channel2 = cvCreateImage(size, depth, 1);
cvSplit(hsvImage, channel0, channel1, channel2, null);
return new IplImageArray(channel0, channel1, channel2);
}
Your error is in this part:
for (i = 0; i < 256; i++) {//draw the histogram
float value = opencv_legacy.cvQueryHistValue_1D(hist, i);
float nextValue = opencv_legacy.cvQueryHistValue_1D(hist, i + 1);
You use i+1 and it causes the error out of range, you can use your for until 255 to correct it.
I hope I helped you. GL