我們想知道是否有可能執行類似附圖的操作。GIF或PNG圖像上的顏色檢測
我們在我們的網站上有一個實時氣象雷達,投影在谷歌地圖頁面上,更新週期爲5分鐘。
這是什麼想法?
我們想爲我們的遊客探測到「沉重的」風暴,並用方箱或其他東西來突出它們。如果可能的話,我們想用PHP製作這個系統。我認爲最好的方法是檢測顏色或其他東西?
附爲例,我們用Photoshop繪製的圖片:
我們希望有人能幫助我們,所以我們可以開始使用的東西!
我們想知道是否有可能執行類似附圖的操作。GIF或PNG圖像上的顏色檢測
我們在我們的網站上有一個實時氣象雷達,投影在谷歌地圖頁面上,更新週期爲5分鐘。
這是什麼想法?
我們想爲我們的遊客探測到「沉重的」風暴,並用方箱或其他東西來突出它們。如果可能的話,我們想用PHP製作這個系統。我認爲最好的方法是檢測顏色或其他東西?
附爲例,我們用Photoshop繪製的圖片:
我們希望有人能幫助我們,所以我們可以開始使用的東西!
我對此進行了另一次嘗試,使用我在C中編寫的一些Connected Component Analysis
軟件。它很容易在任何OS X/Linux/Windows機器上編譯。
所以,這裏是腳本:
#!/bin/bash
# Make red areas white and all else black for blob analysis
convert http://i.stack.imgur.com/qqein.png \
-fuzz 50% \
-fill white +opaque red \
-fill black -opaque red -colorspace gray -negate -depth 16 weather.pgm
# Run Connected Component Analysis to find white blobs and their areas and bounding boxes
./cca <weather.pgm> /dev/null 2> info.txt
# Find blobs with more than 100 pixels
while read a b ;do
draw="$draw -draw \"rectangle $a $b\" "
done < <(awk '/Area/{area=$5+0;if(area>100)print $7,$8}' info.txt)
# Now draw the rectangles on top of the source image
eval convert http://i.stack.imgur.com/qqein.png -strokewidth 2 -stroke red -fill none "$draw" result.png
文件weather.pgm
出來是這樣的:
部分輸出的cca
程序
DEBUG: New blob (1) started at [1][510]
INFO: Blob 1, Area: 8, Bounds: 510,1 510,8
DEBUG: New blob (2) started at [1][554]
INFO: Blob 2, Area: 6, Bounds: 554,1 559,1
DEBUG: New blob (3) started at [2][550]
INFO: Blob 3, Area: 1, Bounds: 550,2 550,2
DEBUG: New blob (4) started at [3][524]
INFO: Blob 4, Area: 1, Bounds: 524,3 524,3
DEBUG: New blob (5) started at [3][549]
INFO: Blob 5, Area: 1, Bounds: 549,3 549,3
DEBUG: New blob (6) started at [3][564]
INFO: Blob 6, Area: 1, Bounds: 564,3 564,3
DEBUG: New blob (7) started at [4][548]
INFO: Blob 7, Area: 1, Bounds: 548,4 548,4
DEBUG: New blob (8) started at [5][526]
INFO: Blob 8, Area: 1, Bounds: 526,5 526,5
DEBUG: New blob (9) started at [5][546]
在腳本的最後convert
命令被稱爲是這樣的:
convert http://i.stack.imgur.com/qqein.png -strokewidth 2 -stroke red -fill none \
-draw 'rectangle 930,125 958,142' -draw 'rectangle 898,138 924,168' \
-draw 'rectangle 822,143 846,172' -draw 'rectangle 753,167 772,175' \
-draw 'rectangle 658,181 758,215' -draw 'rectangle 759,186 803,197' \
-draw 'rectangle 340,223 372,267' -draw 'rectangle 377,259 429,294' \
-draw 'rectangle 977,281 988,357' -draw 'rectangle 705,321 751,351' \
-draw 'rectangle 624,376 658,412' -draw 'rectangle 357,485 380,499' result.png
,結果是這樣的:
的cca.c
程序是這樣的:
/*******************************************************************************
File: cca.c
Author: Mark Setchell
Description:
Connected Components Analyser and Labeller - see algorithm at
http://en.m.wikipedia.org/wiki/Connected-component_labeling#One-pass_version
Algorithm
=========
1. Start from the first pixel in the image. Set "curlab" (short for "current label") to 1. Go to (2).
2. If this pixel is a foreground pixel and it is not already labelled, then give it the label "curlab" and add it as the first element in a queue, then go to (3). If it is a background pixel, then repeat (2) for the next pixel in the image.
3. Pop out an element from the queue, and look at its neighbours (based on any type of connectivity). If a neighbour is a foreground pixel and is not already labelled, give it the "curlab" label and add it to the queue. Repeat (3) until there are no more elements in the queue.
4. Go to (2) for the next pixel in the image and increment "curlab" by 1.
CurrentLabel=1
for all pixels in image
if this is a foreground pixel
if this pixel is not already labelled
label this pixel with Currentlabel
add this pixel to queue
while there are items in the queue
pop item from queue
for all 4-connected or 8-connected neighbours of this item
if neighbour is foreground and is not already labelled
label this neighbour with Currentlabel
add this neighbour to the queue
endif
endfor
endwhile
increment Currentlabel
endif
else
label as background in output image
endif
endfor
Usage
=====
Usage: cca [-c 4|8] <Binarized16BitPGMFile> Binarized16BitPGMFile
where "-c" specifies whether pixels must be 4- or 8-connected to be considered
as parts of same object. By default 4-connectivity is assumed.
Files can be prepared for this program with ImageMagick as follows:
convert YourImage.[jpg|bmp|png|tif] \
-colorspace gray \
-threshold 50% \
-depth 16 \
[-negate] \
FileForAnalysis.pgm
This program expects the background pixels to be black and the objects to be
white. If your image is inverted relative to this, use the "-negate" option.
On OSX, run and view results with ImageMagick like this:
cca < test1.pgm | convert PGM:- -auto-level a.jpg && open a.jpg
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#define DEFAULT_CONNECTIVITY 4
void Usage() {
printf("Usage: cca [-c 4|8] <InputImage.pgm> OutputImage.pgm\n");
exit(EXIT_FAILURE);
}
int pixelIsForegroundAndUnlabelled(uint16_t **iIm,uint16_t **oIm,int height,int width,int row,int col){
if((row<0)||(row>=height)||(col<0)||(col>=width)) return 0;
return (iIm[row][col]!=0) && (oIm[row][col]==0);
}
// Stuff needed for queue
int count=0;
struct node
{
int x,y;
struct node *p;
} *top,*tmp;
void push(int row,int col){
if(top==NULL)
{
top =(struct node *)malloc(sizeof(struct node));
top->p = NULL;
top->x = row;
top->y = col;
}
else
{
tmp =(struct node *)malloc(sizeof(struct node));
tmp->p = top;
tmp->x = row;
tmp->y = col;
top = tmp;
}
count++;
}
void pop(int *x,int *y){
tmp = top;
tmp = tmp->p;
*x = top->x;
*y = top->y;
free(top);
top = tmp;
count--;
}
int main (int argc, char ** argv)
{
int i,reqcon;
int connectivity=DEFAULT_CONNECTIVITY;
uint16_t currentlabel=1;
while (1) {
char c;
c = getopt (argc, argv, "c:");
if (c == -1) {
break;
}
switch (c) {
case 'c':
reqcon=atoi(optarg);
/* Permitted connectivity is 4 or 8 */
if((reqcon!=4)&&(reqcon!=8)){
Usage();
}
connectivity=reqcon;
break;
case '?':
default:
Usage();
}
}
int width,height,max;
int row,col;
/* Check it is P5 type */
char type[128];
fscanf(stdin,"%s",type);
if (strncmp(type,"P5",2)!=0) {
fprintf(stderr, "ERROR: The input data is not binary PGM, i.e. not type P5\n");
exit(EXIT_FAILURE);
}
fscanf(stdin,"%d %d\n",&width,&height);
fscanf(stdin,"%d",&max);
fgetc(stdin);
/* Check 16-bit */
if (max != 65535){
fprintf(stderr, "ERROR: The input data is not 16-bit\n");
exit(EXIT_FAILURE);
}
// Allocate space for input & output image & read input image
uint16_t **iIm; // pixels of input image
uint16_t **oIm; // pixels of output image
iIm = (uint16_t**)malloc(height * sizeof(uint16_t *));
oIm = (uint16_t**)malloc(height * sizeof(uint16_t *));
if((iIm==NULL)||(oIm==NULL)){
fprintf(stderr, "ERROR: out of memory\n");
exit(EXIT_FAILURE);
}
for(i=0;i<height;i++)
{
iIm[i] = (uint16_t*) malloc(width*sizeof(uint16_t));
oIm[i] = (uint16_t*) calloc(width,sizeof(uint16_t));
if((iIm[i]==NULL)||(oIm[i]==NULL)){
fprintf(stderr, "ERROR: Unable allocate memory\n");
exit(EXIT_FAILURE);
}
// Read in one row of image
if(fread(iIm[i],sizeof(uint16_t),width,stdin)!=width){
fprintf(stderr,"ERROR: Reading input file\n");
exit(EXIT_FAILURE);
}
}
// Start of algorithm
for(row=0;row<height;row++){
for(col=0;col<width;col++){
// If this is a foreground pixel that is not yet labelled
if(pixelIsForegroundAndUnlabelled(iIm,oIm,height,width,row,col)){
fprintf(stderr,"DEBUG: New blob (%d) started at [%d][%d]\n",currentlabel,row,col);
int ThisBlobPixelCount=1;
int ThisBlobrmin=row;
int ThisBlobrmax=row;
int ThisBlobcmin=col;
int ThisBlobcmax=col;
oIm[row][col]=currentlabel; // Label the pixel
push(row,col); // Put it on stack
while(count>0){ // While there are items on stack
int tr,tc;
pop(&tr,&tc); // Pop x,y of queued pixel from stack
// Work out who the neighbours are
int neigh[][2]={{tr-1,tc},{tr+1,tc},{tr,tc-1},{tr,tc+1}};
if(connectivity==8){
neigh[4][0]=tr-1; neigh[4][3]=tc-1;
neigh[5][0]=tr+1; neigh[5][4]=tc+1;
neigh[6][0]=tr+1; neigh[6][5]=tc-1;
neigh[7][0]=tr-1; neigh[7][6]=tc+1;
}
// Process all neighbours
for(i=0;i<connectivity;i++){
int nr=neigh[i][0];
int nc=neigh[i][7];
if(pixelIsForegroundAndUnlabelled(iIm,oIm,height,width,nr,nc)){
oIm[nr][nc]=currentlabel;
push(nr,nc);
ThisBlobPixelCount++;
if(nr<ThisBlobrmin)ThisBlobrmin=nr;
if(nr>ThisBlobrmax)ThisBlobrmax=nr;
if(nc<ThisBlobcmin)ThisBlobcmin=nc;
if(nc>ThisBlobcmax)ThisBlobcmax=nc;
}
}
}
// Output statistics/info about the blob we found
fprintf(stderr,"INFO: Blob %d, Area: %d, Bounds: %d,%d %d,%d\n",currentlabel,ThisBlobPixelCount,ThisBlobcmin,ThisBlobrmin,ThisBlobcmax,ThisBlobrmax);
currentlabel++; // Increment label as we have found all parts of this blob
}
}
}
// Write output image
fprintf(stdout,"P5\n%d %d\n65535\n",width,height);
for(row=0;row<height;row++){
if(fwrite(oIm[row],sizeof(uint16_t),width,stdout)!=width){
fprintf(stderr,"ERROR: Writing output file\n");
exit(EXIT_FAILURE);
}
}
return EXIT_SUCCESS;
}
正確的方法做,很可能會使用某種斑點分析的提取紅色區域並做邊界周圍盒。這並不難,但在開始這種方法時,我可以用一行ImageMagick來做更簡單但相當有效的事情。它在命令行以及PHP,Perl,Python和其他綁定中都是免費的。因此,我打算將所有紅色區域轉換爲白色,並將所有非紅色區域轉換爲黑色,然後運行Blob分析並在白色斑點周圍繪製紅色邊界框。但在途中,我想可能會讓圖像的非紅色區域變爲半透明區域,然後再將紅色區域完全透明化,所以關注的焦點是紅色的東西,其他所有東西都很蒼白。這可以在一個單一的ImageMagick命令來完成這樣的:
convert http://i.stack.imgur.com/qqein.png \
\(+clone \
-fuzz 30% \
-fill "#222222" +opaque red \
-fill "#ffffff" -opaque red -colorspace gray \) \
-compose copy-opacity -composite out.png
的結果是這樣的:
,如果你喜歡的方法的數字可以明顯地調整了...
** + 1 **也非常好的方法:-) –
我會通過使用-fx運算符來隔離紅色單元格。
convert source.png -fx '(p.r > p.b && p.r > 0.9) ? p : 0' a_RED.png
的p.r > p.b
除去白色的顏色,以及對的0.9
的閾值的當前像素p.r > 0.9
檢查。
這種方法需要一些額外的CPU時間,但確實能夠調整嚴重程度。
** + 1 **非常高雅:-) –
我才發現,原來ImageMagick
可以做連成分分析所以我現在可以提供不依賴於我的C代碼更簡單的解決方案。
這就是:
#!/bin/bash
draw=$(convert http://i.stack.imgur.com/qqein.png \
-fuzz 50% \
-fill white +opaque red \
-fill black -opaque red \
-colorspace gray \
-define connected-components:verbose=true \
-define connected-components:area-threshold=100 \
-connected-components 8 \
-auto-level baddies.png | \
awk 'BEGIN{command=""}
/\+0\+0/||/id:/{next}
{
geom=$2
gsub(/x/," ",geom)
gsub(/+/," ",geom)
split(geom,a," ")
d=sprintf("-draw \x27rectangle %d,%d %d,%d\x27 ",a[3],a[4],a[3]+a[1],a[4]+a[2])
command = command d
#printf "%d,%d %d,%d\n",a[3],a[4],a[3]+a[1],a[4]+a[2]
}
END{print command}')
eval convert http://i.stack.imgur.com/qqein.png -fill none -strokewidth 2 -stroke red $draw out.png
這裏是產生的圖像:
,並在這裏從文件標記的對象baddies.png
這裏有索姆e關於代碼的說明...
-fuzz 50%允許一些程度的變化中的紅色
-fill白色不透明+紅色檢測到的色調 - 改變所有紅色像素,以白色
-fill黑色-opaque紅色 - 將所有非紅色像素更改爲黑色
-define connected-components:verbose = true - 導致診斷輸出,所以我可以ge噸邊界框它找到
-define連接組件:區域閾值= 100 - 說我只在尺寸100個像素或更大
- 連通組件8紅色區域有興趣 - 說紅點可以連接到他們的8鄰居(即斜加盟,而不是方加入)
- 自動水平baddies.png - 對比度拉伸標記風暴的對象並將它們保存在一個名爲baddies.png
的awk
東西文件就像awk
東西在我的其他答案。
只是爲了讓別人看到ImageMagick的連接成分分析的輸出在第一階段,它看起來像這樣:
Objects (id: bounding-box centroid area mean-color):
0: 1020x563+0+0 507.6,281.2 567516 gray(253)
495: 53x36+377+259 405.3,273.3 1040 gray(0)
391: 101x35+658+181 699.9,195.6 984 gray(0)
515: 13x77+976+281 982.5,321.4 863 gray(0)
581: 35x37+624+376 641.9,397.1 740 gray(0)
439: 33x45+340+223 352.0,249.2 643 gray(1)
558: 47x32+705+320 727.2,334.8 641 gray(1)
353: 25x30+822+143 834.3,156.1 422 gray(0)
350: 27x31+898+138 911.4,152.7 402 gray(0)
343: 29x18+930+125 944.6,132.2 283 gray(0)
392: 45x12+759+186 783.0,193.0 276 gray(0)
663: 24x15+357+485 367.3,493.4 192 gray(0)
531: 98x58+169+297 209.4,336.2 152 gray(0)
377: 20x9+753+167 762.6,170.6 106 gray(0)
到最終convert
命令的參數如下所示:
convert http://i.stack.imgur.com/qqein.png -fill none -strokewidth 2 -stroke red \
-draw 'rectangle 377,259 430,295' \
-draw 'rectangle 658,181 759,216' \
-draw 'rectangle 976,281 989,358' \
-draw 'rectangle 624,376 659,413' \
-draw 'rectangle 340,223 373,268' \
-draw 'rectangle 705,320 752,352' \
-draw 'rectangle 822,143 847,173' \
-draw 'rectangle 898,138 925,169' \
-draw 'rectangle 930,125 959,143' \
-draw 'rectangle 759,186 804,198' \
-draw 'rectangle 357,485 381,500' \
-draw 'rectangle 169,297 267,355' \
-draw 'rectangle 753,167 773,176' out.png
** + 1 ** - 好的! (你是否也可以提出這個問題本身 - 它不應該得到downvote [沒有*我的* upvote補償]? - 當你在這個問題上,你可以閱讀[這個問題](http:///stackoverflow.com/q/23495372/359307)並投票重新打開,如果你同意我的意見 - 謝謝。) –
完美的答案。正是我們需要的! – user3408380
在Python中這也是可能的,這對我們來說會更容易!謝謝:) – user3408380