Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have several bitmaps images and want to segment and access the position (and want know the size) of the continuous tone very high correlated areas,I mean by continues tone areas (high correlated segments) only the the areas that hold the exact same values of pixels. I have experience in image processing and am using c++ and opencv but i didnt find a library doing that am afraid if I do the programming I will lose the performance and the calculation became inefficient while I need to process further a lot of things. in this time but due to 10 years of this science leaving I became clumsy and I cant find the answers as I were young, I will be grateful if you help me in any ideas about that because am stuck. thanks for the kind reading and help.
I can demonstrate the concept of my comment using ImageMagick, and this test image which has the useful property of being noise which means you can see it on SO's white background and the algorithm shouldn't see it.
I can average it over an area of 15x15 like this:
convert test.png -statistic mean 15x15 x.png
which gives this
then threshold and invert it so you can see the areas of continuous tone identified in white
convert test.png -statistic mean 15x15 test.png -compose difference -composite -depth 8 -threshold 1 -negate x.png
You can experiment with different widths and heights of the blurring box like this:
#!/bin/bash
for x in 3 7 15 25; do
for y in 3 7 15 25; do
convert -label "${x}x${y}" test.png -statistic mean ${x}x${y} miff:-
done
done | montage - -frame 5 -tile 4x out.png
which gives this:
and the corresponding masked image thus:
You can the pass that into the Connected Components Analysis like this:
convert test.png -statistic mean 5x5 \
test.png -compose difference -composite \
-depth 8 -threshold 1 -negate \
-define connected-components:verbose=true \
-define connected-components:area-threshold=20 \
-connected-components 8 -auto-level blobs.png
which will give you this which contains the coordinates of the blobs
Objects (id: bounding-box centroid area mean-color):
0: 500x500+0+0 270.8,271.7 177169 srgb(0,0,0)
1: 216x216+52+41 159.5,148.5 46656 srgb(255,255,255)
8: 114x114+63+351 119.5,407.5 10039 srgb(255,255,255)
2: 81x100+354+47 394.0,96.5 8100 srgb(255,255,255)
5: 49x49+348+204 372.0,228.0 2401 srgb(255,255,255)
6: 358x5+55+287 233.5,289.0 1790 srgb(255,255,255)
10: 45x45+244+383 265.9,405.0 1520 srgb(255,255,255)
3: 4x289+451+181 452.5,325.0 1156 srgb(255,255,255)
7: 122x4+57+309 117.5,310.5 488 srgb(255,255,255)
9: 4x114+416+356 417.5,412.5 456 srgb(255,255,255)
4: 15x15+312+185 319.0,192.0 225 srgb(255,255,255)
I can then outline the detected areas on top of the original image:
Related
I am trying to automate image conversion using ImageMagick CLI. One of the biggest problems with my image set is with tiny artifacts that should be cut out.
My images are generally consistent, with big objects (c.a. 50% of image space) on a white background. Unfortunately, sometimes tiny artifacts may just look bad and make trimming less efficient.
E.g. something like that:
In reality, the big object is not a solid color, it's just a simplified example. It is not necessarily a circle either, it can be a square, rectangle, or something irregular.
I cannot also use any morphology like opening, closing, or erosion. Filters like gaussian or median also are out of the question. I need to keep the big object untouched since the highest possible quality is required.
An ideal solution would be something similar to Contours known for example from OpenCV, where I could find all the uniform objects and if they don't meet certain rules (e.g. threshold of size greater than 5% of the whole image) - fill them with white color.
Is there any similar mechanism in ImageMagick CLI? I've gone through the docs and haven't found a suitable solution to my problem.
Thanks in advance!
EDIT (ImageMagick version):
Version: ImageMagick 7.1.0-47 Q16-HDRI x86_64 20393 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenMP(5.0)
Delegates (built-in): bzlib fontconfig freetype gslib heic jng jp2 jpeg lcms lqr ltdl lzma openexr png ps raw tiff webp xml zlib
Compiler: gcc (4.2)
EDIT (Real-life example):
As requested, here is a real-life example. A picture of a coin on a white background, but with some artifacts:
noise under the coin (slightly on the left)
dot under the coin (slightly on the right)
gray irregular shape in the top right corner
The objects might not be necessarily circles like coins but we may assume that there always will be one object with a strong border (no white spaces on the border, like here) and the rest is noise.
Here is one way to do that im Imagemagick 7. First threshold the image so the background is white and the object(s) is black. That will likely be image dependent. NOTE: that JPG is a lousy format, since solid colors are not really truly solid due to the compression. If you can save your images in some non-lossy compressed or uncompress format, that would be better. Then decide on the largest area you need to remove. Use that with connected components processing so that you have only two regions, one white background and one black object. This will be a mask. If you have several objects that is fine also, but they need to be black. I show the textual output showing the two regions. The mask is just the object with the noise removed. So now use the original input, a white image and the mask to composite the first two images so that where the mask is black, the object is used and where the mask is white, the white image will be used. Note, I create the white image by making a copy (clone) of the input and colorizing it 100% with white. The following is in Unix syntax.
Input:
magick coin.jpg -negate -threshold 2% -negate -type bilevel \
-define connected-components:verbose=true \
-define connected-components:area-threshold=1000 \
-define connected-components:mean-color=true \
-connected-components 4 mask.png
Objects (id: bounding-box centroid area mean-color):
0: 1000x1000+0+0 525.8,555.7 594824 gray(255)
44: 722x720+101+58 460.9,417.0 405176 gray(0)
magick coin.jpg \
\( +clone -fill white -colorize 100 \) \
mask.png \
-compose over -composite \
coin_result.png
Mask
Result:
See https://imagemagick.org/script/connected-components.php
and https://imagemagick.org/Usage/compose/#compose and Composite Operator of Convert (-composite, -geometry) at https://imagemagick.org/Usage/layers/#convert
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
So I'm staring a project about image processing with C++.
The thing is that everything I find online about this matter (blurring an image in C++) comes either with CUDA or with OpenCV.
Is there a way to blur an image with C++ only? (for starters)
If yes, can somebody please share the code or explain?
Thanks!
Firstly you need the image in memory.
Then you need a second buffer to use as a workspace.
Then you need a filter. A common filter would be
1 4 1
4 -20 4
1 4 1
For each pixel, we apply the filter. So we're setting the image to a weighted average of the pixels around it, then subtracting to avoid the overall image going lighter or darker.
Applying a small filter is very simple.
for(y=0;y<height;y++)
for(x=0;x<width;x++)
{
total = image[(y+1)*width+x+1];
for(fy=0; fy < 3; fy++)
for(fx = 0; fx < 3; fx++)
total += image[(y+fy)*width+x+fx] * filter[fy*3+x];
output[(y+1)*width+x+1] = clamp(total, 0, 255);
}
You need to special case the edges, which is just fiddly but doesn't add any theoretical complexity.
When we use faster algorithms that the naive one it becomes important to set up edges correctly. You then do the calculations in the frequency domain and it's a lot faster with a big filter.
If you would like to implement the blurring on your own, you have to somehow store the image in memory. If you have a black and white image, an
unsigned char[width*height]
might be sufficient to store the image; if it is a colour image, perhaps you will have the same array, but three or four times the size (one for each colour channel and one for the so-called alpha-value which describes the opacity).
For the black and white case, you would have to sum up the neighbours of each pixel and calculate its average; this approach transfers to colour images by applying the operation to each colour channel.
The operation described above is a special case of the so-called kernel filter, which can also be used to implement different operations.
I have rendered multiple images from an application. Here is sample images that illustrate two images that looks almost the same to the eye .
I try to compare them with the following command in image magick.
compare -metric AE img1.png img2.png diff.png
6384
This means 6384 pixels differ even if the images are similar.
I got minor changes like if a pattern is moved 1 pixel to the right this will give me a large error in number of different pixels. Is there a good way of do this kind of diff with ImageMagick? I have experimented with the fuzz parameter, but it really does not help me. Is ImageMagick compare only suited for comparing photographic images? Are there better switches to ImageMagick that can recognize a text that has moved some pixels and report it as equal? Should I use another tool?
Edit:
Adding an example on a image that looks clearly different for a human and will illustrate the kind of difference I am trying to differentiate. In this image not many pixels are changed, but the visible pattern is clearly changed.
It's hard to give any detailed answer as I don't know what you are looking for or expecting. I guess you may need some sort of Perceptual Hash if you are looking for images that people would perceive as similar or dissimilar, or maybe a Scale/Rotation/Translation Invariant technique that identifies similar images independently of resizes, shifts and rotations.
You could look at the Perceptual Hash and Image Moments with ImageMagick like this:
identify -verbose -features 1 -moments 1.png
Image: 1.png
Format: PNG (Portable Network Graphics)
Mime type: image/png
Class: PseudoClass
Geometry: 103x115+0+0
Resolution: 37.79x37.79
Print size: 2.72559x3.04313
Units: PixelsPerCentimeter
Type: Grayscale
Base type: Grayscale
Endianess: Undefined
Colorspace: Gray
Depth: 8-bit
Channel depth:
gray: 8-bit
Channel statistics:
Pixels: 11845
Gray:
min: 62 (0.243137)
max: 255 (1)
mean: 202.99 (0.79604)
standard deviation: 85.6322 (0.335812)
kurtosis: -0.920271
skewness: -1.0391
entropy: 0.840719
Channel moments:
Gray:
Centroid: 51.6405,57.1281
Ellipse Semi-Major/Minor axis: 66.5375,60.336
Ellipse angle: 0.117192
Ellipse eccentricity: 0.305293
Ellipse intensity: 190.641 (0.747614)
I1: 0.000838838 (0.213904)
I2: 6.69266e-09 (0.00043519)
I3: 3.34956e-15 (5.55403e-08)
I4: 5.38335e-15 (8.92633e-08)
I5: 2.27572e-29 (6.25692e-15)
I6: -4.33202e-19 (-1.83169e-09)
I7: -2.16323e-30 (-5.94763e-16)
I8: 3.96612e-20 (1.67698e-10)
Channel perceptual hash:
Red, Hue:
PH1: 0.669868, 11
PH2: 3.35965, 11
PH3: 7.27735, 11
PH4: 7.05343, 11
PH5: 11, 11
PH6: 8.746, 11
PH7: 11, 11
Green, Chroma:
PH1: 0.669868, 11
PH2: 3.35965, 11
PH3: 7.27735, 11
PH4: 7.05343, 11
PH5: 11, 11
PH6: 8.746, 11
PH7: 11, 11
Blue, Luma:
PH1: 0.669868, 0.669868
PH2: 3.35965, 3.35965
PH3: 7.27735, 7.27735
PH4: 7.05343, 7.05343
PH5: 11, 11
PH6: 8.746, 8.746
PH7: 11, 11
Channel features (horizontal, vertical, left and right diagonals, average):
Gray:
Angular Second Moment:
0.364846, 0.615673, 0.372224, 0.372224, 0.431242
Contrast:
0.544246, 0.0023846, 0.546612, 0.546612, 0.409963
Correlation:
-0.406263, 0.993832, -0.439964, -0.439964, -0.07309
Sum of Squares Variance:
1.19418, 1.1939, 1.19101, 1.19101, 1.19253
Inverse Difference Moment:
0.737681, 1.00758, 0.745356, 0.745356, 0.808993
Sum Average:
1.63274, 0.546074, 1.63983, 1.63983, 1.36462
Sum Variance:
4.43991, 0.938019, 4.46048, 4.46048, 3.57472
Sum Entropy:
0.143792, 0.159713, 0.143388, 0.143388, 0.14757
Entropy:
0.462204, 0.258129, 0.461828, 0.461828, 0.410997
Difference Variance:
0.0645055, 0.189604, 0.0655494, 0.0655494, 0.0963021
Difference Entropy:
0.29837, 0.003471, 0.297282, 0.297282, 0.224101
Information Measure of Correlation 1:
-0.160631, -0.971422, -0.146024, -0.146024, -0.356026
Information Measure of Correlation 2:
0.294281, 0.625514, 0.29546, 0.29546, 0.377679
You could also go on Fred Weinhaus's excellent website (here) and download his script called moments which will calculate the Hu and Maitra moments and see if those will tell you what you want. Basically, you could run the script on each of your images like this:
./moments image1.png > 1.txt
./moments image2.png > 2.txt
and then use your favourite diff tool to see what has changed between the two images you wish to compare.
I am still a beginner in coding. I am currently working on a program in C/C++ that is determining pixel position of a defined mark (which is a black circle with white surroundings) in a photo.
I made a mask from the mark and a vector, which contains mask's every pixel value as it's elements (using Magick++ I summed values for Red, Green and Blue). Vector contains aprox. 10 000 values since the mask is 100x100px. I also used threshold functions for simplifying the image.
Than I made a grid, that is doing the same for the picture, where I want to find the coordinates of the mark. It is basically a loop, that is going throught the image and when the program knows pixel values in the grid it immediately compares them with the mask. Main idea is to find lowest difference between the mask and one of the grid positions.
The problem is however that this procedure of evaluating all grids position takes huge amount of time (e.g. the image has 1920x1080px so more than 2 million vectors containing 10 000 values). I decided to cycle the grid not every pixel but for example every 10th column and row, and than for the best corellation from this procedure I selected area where I used every pixel loop. But, this still takes lot of time.
I would like to ask you, if there is some way of improving this method for better (faster) results or this whole idea is not time efficient and I should use different approach.
Thanks for every advice!
Edit: The program will be used for processing multiple images and on all of them the size will be same. This is the picture after threshold, the mark is the big black dot.
Image
The idea that I find interesting is a pyramidal scheme - or progressive refinement: you find the spot at a lower size image then search only a small rectangle in the larger image.
If you reduce your image by 2 in each dimension then you would reduce the time by 4 plus some search effort in the larger image.
This has some problems: the reduction will affect accuracy I expect. You might miss the spot.
You have to cut the sample (template) by the same so you create a half-size template in this case. As you half half half... the template will get blurred into the surrounding objects so it will not be possible to have a valid template; for half size once I guess the dot has a couple of pixels around it.
As you haven't specified a tool or OS, I will choose ImageMagick which is installed on most Linux distros and is available for OSX and Windows. I am just using it at the command-line here but there are C, C++, Python, Perl, PHP, Ruby, Java and .Net bindings available.
I would use a "Connect Components Analysis" or "Blob Analysis" like this:
convert image.png -negate \
-define connected-components:area-threshold=1200 \
-define connected-components:verbose=true \
-connected-components 8 -auto-level result.png
I have inverted your image with -negate because in morphological operations, the foreground is usually white rather than black. I have excluded blobs smaller than 1200 pixels because your circles seem to have a radius of 22 pixels which makes for an area of 1520 pixels (Pi * 22^2).
That gives this output, which means 7 blobs - one per line - with the bounding box and area of each:
Objects (id: bounding-box centroid area mean-color):
0: 1358x1032+0+0 640.8,517.0 1296947 gray(0)
3: 341x350+1017+287 1206.5,468.9 90143 gray(255)
106: 64x424+848+608 892.2,829.3 6854 gray(255)
95: 38x101+44+565 61.5,619.1 2619 gray(255)
49: 17x145+1341+379 1350.3,446.7 2063 gray(0)
64: 43x43+843+443 864.2,464.1 1451 gray(255)
86: 225x11+358+546 484.7,551.9 1379 gray(255)
Note that, as your circle is 42x42 pixels you will be looking for a blob that is square-ish and close to that size - so I am looking at the second to last line. I can draw that in in red on your original image like this:
convert image.png -fill none -stroke red -draw "rectangle 843,443 886,486" result.png
Also, note that as you are looking for a circle, you would expect the area to be pi * r^2 or around 1500 pixels and you can check that in the penultimate column of the output.
That runs in 0.4 seconds on a reasonable spec iMac. Note that you could divide the image into 4 and run each quarter in parallel to speed things up. So, if you do something like this:
#!/bin/bash
# Split image into 4 (maybe should allow 23 pixels overlap)
convert image.png -crop 1x4# tile-%02d.mpc
# Do Blob Analysis on 4 strips in parallel
for f in tile-*mpc; do
convert $f -negate \
-define connected-components:area-threshold=1200 \
-define connected-components:verbose=true \
-connected-components 8 info: &
done
# Wait for all 4 to finish
wait
That runs in around 0.14 seconds.
Hello there and thank you for at the very least, trying to help me.
I need to, firstly, load an image and then loop through all pixels of that image and check the color of each pixel.
I have never tried messing around with images or whatnot.
Any help is greatly appreciated.
Thank you.
Looking at the bigger picture, of counting the dots on a dice, I would look at using ImageMagick - with the C++ binding called Magick++ from here
I would be looking at using "Blob Analysis", or "Connected Component Analysis" to count the dots on a dice.
Using this dice...
If I use ImageMagick at the command line like this:
convert dice.png -colorspace gray -threshold 50% \
-define connected-components:verbose=true \
-define connected-components:area-threshold=10 \
-connected-components 8 -auto-level output.png
Output
Objects (id: bounding-box centroid area mean-color):
0: 380x362+0+0 189.6,180.0 103867 srgba(255,255,255,1)
2: 93x92+248+32 293.8,77.5 6743 srgba(0,0,0,1)
4: 92x93+39+241 84.8,286.7 6741 srgba(0,0,0,1)
5: 93x93+248+241 293.8,286.8 6738 srgba(0,0,0,1)
1: 92x92+39+32 84.8,77.5 6736 srgba(0,0,0,1)
3: 93x93+143+136 189.3,182.1 6735 srgba(0,0,0,1)
You can see it has found 5 dots (the first one is actually the whole, white image), and I can put a red box around each dot like this so you can see what it has found:
convert dice.png -stroke red -fill none -strokewidth 1 -draw "rectangle 248,32 341,124" -draw "rectangle 39,241 131,334" -draw "rectangle 248,241 341,334" -draw "rectangle 39,32 131,124" -draw "rectangle 143,136 236,229" result.png
I think you may use OpenCV image processing library. You have a detailed manual for installing for VS2013 here:
OpenCV installation for Visual Studio 2013
After you've installed it. You will get a lot of functions for image processing, including what you are looking for.
For example:
Mat inputImage = imread(filename, CV_LOAD_IMAGE_COLOR);
then:
Cycle through pixels with opencv
One of the methods you could use, is to interpret the file as binary. If you know how to interpret the header part and know what color depth the image has (the header has such info), then it wont be a longshot to just compare binary or hexadecimal color codes - probably hexadecimal since C++ doesnt have a built in binary variable.
if you dont think you can handle binary and need a library to work with, refer to
How do I read JPEG and PNG pixels in C++ on Linux?
EDIT - or just use any image processing libraries such as http://cimg.eu since the objective appears to be interpretation of dice from an image.