I have this image.
Image of a map
I want to:-
1. Recognize all the regions in this image
2. Recognize which region is connected to other regions
My goal is to apply four color theorem in this image and output a properly colored image. I'm a beginner in both python and opencv.
Your assistance in this matter would be greatly appreciated.
here is a MATLAB code which does what you want. It shouldn't be too complicated to implement it in Python+OpenCV:
% read image
m = rgb2gray(imread('map.jpg'));
% remove noise
m = medfilt2(m);
b = m < 250;
se1 = strel('disk',1,0);
se2 = ones(7);
b = imclose(imopen(b,se1),se2);
% skeletonize
B = bwmorph(b,'skel',inf);
% remove background
R = padarray(~B,[1 1],1);
bg = bwselect(R,1,1,4);
R(bg) = 0;
R = R(2:end-1,2:end-1);
% get regions connected components
ccRegions = bwconncomp(R,4);
maskRegions = false([size(R),ccRegions.NumObjects]);
MAP = zeros(size(R));
% generate a binary mask for each region, dilate it to detect overlaps
% between neigbors
for ii = 1:ccRegions.NumObjects
maskRegions((ii - 1)*numel(R) + (ccRegions.PixelIdxList{ii})) = 1;
maskRegions(:,:,ii) = imdilate(maskRegions(:,:,ii),se1);
MAP(maskRegions(:,:,ii)) = ii;
end
% detect neighbors using masks overlapping
neighborsRegions = cell(ccRegions.NumObjects,1);
for ii = 1:ccRegions.NumObjects
r = repmat(maskRegions(:,:,ii),[1 1 ccRegions.NumObjects]);
idxs = any(any(r & maskRegions,1),2); %indexes of touching neighbors
idxs(ii) = 0; % remove self index
neighborsRegions{ii} = find(idxs);
end
% show result
imshow(MAP,[])
c = regionprops(ccRegions,'Centroid');
for ii = 1:ccRegions.NumObjects
text(c(ii).Centroid(1),c(ii).Centroid(2),num2str(ii),'FontSize',20,'Color','r');
end
The output looks like that:
And the neighbors of each region is:
neighborsRegions = {[2;3]
[1;3;4]
[1;2;4;5;6]
[2;3;6]
[3;6]
[3;4;5]
[]}
Related
I am implementing a conference paper and it was originally in matlab and I translated it into python to process it with opencv using fuzzy contextual contrast enhancement method attached paper here in gdrive for reference.
Research Paper Drive link open to all
import cv2
import math
import numpy as np
image = cv2.imread('img1.bmp')
CIm = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
a=CIm[:,:,2]
Im = a/255
def f1(num):
return math.floor(num*10000)
Im = np.vectorize(f1)(Im)
rows = Im.shape[0]
cols = Im.shape[1]
Ffactor = np.zeros(Im.shape,dtype = int)
H = np.zeros((10001,1),dtype=float)
w=1
width = round(np.std(Im.astype(float)))
for i in range(rows):
for j in range(cols):
totf = 0.0
count = 0
f = 0.0
for ii in range(-w,w+1):
for jj in range(-w,w+1):
if (i + ii >= 0 and i + ii < rows and j + jj >= 0 and j + jj < cols):
count = count + 1 ;
temp = float(Im[i + ii,j + jj]) - float(Im[i,j])
f = max(min(1-abs(temp/width),1),0)
totf = totf + (f)
t = totf/9
print(count)
Ffactor[i,j] = t
H[Im[i,j]] = H[Im[i,j]] + math.log2(t)**2
Hpdf = H/np.sum(H)
#total = np.sum(H)
#for k in range(H.shape[0]):
# Hpdf[k] = H[k]/total
def FHE(Im,Ffactor ,Hpdf, lval, hval):
Hcdf = np.cumsum(Hpdf)
m=np.mean(Im,dtype=float)
s=np.std(Im,dtype=float)
delta = s/m
for i in range(Im.shape[0]):
for j in range(Im.shape[1]):
temp = lval + round(( hval- lval) * Hcdf[Im[i,j]] )
Im[i,j] = ((temp - float(Im[i,j])) * math.exp((-(Ffactor[i,j])**2)*1*delta) + Im[i,j])
return Im
Imf = FHE(Im, Ffactor,Hpdf, 0, 10000)
Imf = Imf/10000
Imf = Imf*255
Imf = np.vectorize(round)(Imf)
CIm[:,:,2] = Imf;
Im_out = cv2.cvtColor(CIm, cv2.COLOR_HSV2BGR)
cv2.imshow('Original image',image)
cv2.imshow('equalised image', Im_out)
cv2.waitKey(0)
cv2.destroyAllWindows()
Source Image
processed Image
I don't get that why i am getting jigsaw puzzles in my processed image ??
I ran it with other pictures and it worked fine but with this particular picture it gives me this boxes everywhere and i can't figure out why ??
i was running original code of paper which was in matlab and it was better and worked fine without boxes.
I want to remove these boxes in my processed image pls check where fault lies in code.
I came across this particular color-transfer tutorial using OpenCV:
https://www.pyimagesearch.com/2014/06/30/super-fast-color-transfer-images/
and implemented it like this:
def color_transfer(source, target):
# compute color statistics for the source and target images
source = cv2.cvtColor(source, cv2.COLOR_BGR2LAB).astype("float32")
target = cv2.cvtColor(target, cv2.COLOR_BGR2LAB).astype("float32")
# compute color stats for both images
(lMeanSrc, lStdSrc, aMeanSrc, aStdSrc, bMeanSrc, bStdSrc) = self.image_stats(source)
(lMeanTar, lStdTar, aMeanTar, aStdTar, bMeanTar, bStdTar) = self.image_stats(target)
# split the color space
(l, a, b) = cv2.split(target)
# substract the means from target image
l -= lMeanTar
a -= aMeanTar
b -= bMeanTar
# check values
print(lStdSrc, aStdSrc, bStdSrc)
print(lStdTar, aStdTar, bStdTar)
print(lMeanSrc, aStdSrc, bMeanSrc)
# process lab computation
l = (lStdSrc / lStdTar) * l
a = (aStdSrc / aStdTar) * a
b = (bStdSrc / bStdTar) * b
# add the source mean
l += lMeanSrc
a += aMeanSrc
b += bMeanSrc
# clipping the pixels between 0 and 255
l = np.clip(l, 0, 255)
a = np.clip(a, 0, 255)
b = np.clip(b, 0, 255)
# merge the channels
transfer = cv2.merge([l, a, b])
# converting back to BGR
transfer = cv2.cvtColor(transfer.astype("uint8"), cv2.COLOR_LAB2BGR)
return transfer
In this particular code:
# process lab computation
l = (lStdSrc / lStdTar) * l
a = (aStdSrc / aStdTar) * a
b = (bStdSrc / bStdTar) * b
it gets the standard deviation of the source, so when we combine the source and the target image, it will become a plain image as well since the lab will all be 0.
How can I fix this? It works when the source image is not a plain image with color.
I am a complete beginner I am trying to obtain real depth map from left and right image. I've used OpenCV to get the disparity map via block matching as you can see in the code bellow.
import cv2
import cv2.cv as cv
import sys
import numpy as np
def getDisparity(imgLeft, imgRight, method="BM"):
gray_left = cv2.cvtColor(imgLeft, cv.CV_BGR2GRAY)
gray_right = cv2.cvtColor(imgRight, cv.CV_BGR2GRAY)
print gray_left.shape
c, r = gray_left.shape
if method == "BM":
sbm = cv.CreateStereoBMState()
disparity = cv.CreateMat(c, r, cv.CV_32F)
sbm.SADWindowSize = 11
sbm.preFilterType = 1
sbm.preFilterSize = 5
sbm.preFilterCap = 61
sbm.minDisparity = -50
sbm.numberOfDisparities = 112
sbm.textureThreshold = 507
sbm.uniquenessRatio= 0
sbm.speckleRange = 8
sbm.speckleWindowSize = 0
gray_left = cv.fromarray(gray_left)
gray_right = cv.fromarray(gray_right)
cv.FindStereoCorrespondenceBM(gray_left, gray_right, disparity, sbm)
disparity_visual = cv.CreateMat(c, r, cv.CV_8U)
cv.Normalize(disparity, disparity_visual, 0, 255, cv.CV_MINMAX)
disparity_visual = np.array(disparity_visual)
elif method == "SGBM":
sbm = cv2.StereoSGBM()
sbm.SADWindowSize = 9;
sbm.numberOfDisparities = 0;
sbm.preFilterCap = 63;
sbm.minDisparity = -21;
sbm.uniquenessRatio = 7;
sbm.speckleWindowSize = 0;
sbm.speckleRange = 8;
sbm.disp12MaxDiff = 1;
sbm.fullDP = False;
disparity = sbm.compute(gray_left, gray_right)
disparity_visual = cv2.normalize(disparity, alpha=0, beta=255, norm_type=cv2.cv.CV_MINMAX, dtype=cv2.cv.CV_8U)
return disparity_visual
imgLeft = cv2.imread('1.png')
imgRight = cv2.imread('2.png')
try:
method = "BM"
except IndexError:
method = "BM"
disparity = getDisparity(imgLeft, imgRight, method)
cv2.imshow("disparity", disparity)
#cv2.imshow("left", imgLeft)
#cv2.imshow("right", imgRight)
cv2.waitKey(0)
My question is what is the easiest way to obtain real depth map (distance) from disparity using python?
In order to calculate depth for stereo, you need to know the translation and rotation between the cameras. If you have that, you can take each disparity value and use triangulation to calculate the depth for that 3D point.
I recommend reading http://www.robots.ox.ac.uk/~vgg/hzbook/
for a detailed explanation.
Assuming your cameras are calibrated, the images rectified, you can use the formula provided by this tutorial which is:
disparity = Baseline * focal-lens / depth
So,
depth = Baseline * focal-lens / disparity
I have a program which gets the contours of an image. I want to break these contours into sub-contours based on relative straightness. If the straightness of an extra pixel is less than a threshold value times the previous straightness, the contour should be split. When I put an image of a square drawn in paint, the program output should be 4 sub-contours. However, for some reason I get 3 sub-contours with 2 of them including 2-3 points and one including most of the original contour. Note, the 0.85 in my code is a threshold derived from a research paper. dPreious is the pixel distance of the edge(Not Including the Current Pixel). v is the euclidean distance between end-points.
def split(contour):
new = [];
toAdd = [];
sCurrent = 0.0
sPrevious = 0.0
v = 0.0
dPrevious = 1
for points in range(0,len(contour)):
currentX = float(contour[points][0])
currentY = float(contour[points][1])
if points != 0:
v = math.sqrt(math.pow(float(toAdd[0][0])-currentX,2) + math.pow(float(toAdd[0][1])-currentY,2))
dPrevious = len(toAdd)
sCurrent = v/dPrevious
if sCurrent < 0.85*sPrevious:
new.append(toAdd)
toAdd = []
toAdd.append(contour[points])
sPrevious = sCurrent
new.append(toAdd)
return new
If you use OpenCV for finding the contours you can use the functionality of the cv2.approxPolyDP() function to do the job for you:
cv2.approxPolyDP. You might have to experiment with the epsilon parameter to have succes with it.
I am trying to view my local ridge orientation of a fingerprint as a flowchart. But I seem to fail miserably at doing so. My method consists of the following steps:
use the lro function
find the most dominant angle in a 16x16 block
create a line segment and rotate it by the dominant angle to display it
The problem is that while the angles that the lro produces are good, the display of these in the flowchart does not work at all. There I just get a lot of random angles going in all kind of directions. Can anyone help me solve this problem?
Here is the code I'm using:
def lro(im_np):
eps = 2**(-52)
orientsmoothsigma = 4
# original
Gxx = cv2.Sobel(im_np, -1, 2, 0)
Gxy = cv2.Sobel(im_np, -1, 1, 1)
Gyy = cv2.Sobel(im_np, -1, 0, 2)
Gxx = scipy.ndimage.filters.gaussian_filter(Gxx, orientsmoothsigma)
Gxy = scipy.ndimage.filters.gaussian_filter(Gxy, orientsmoothsigma)
Gyy = scipy.ndimage.filters.gaussian_filter(Gyy, orientsmoothsigma)
angle = math.pi/2. + numpy.divide(numpy.arctan2(numpy.multiply(Gxy,2), numpy.subtract(Gxx,Gyy)),2)
return angle
def createLine(im_np):
#Assumes it is 17x17
#Takes in the block-direction
#returns a block-direction image as a numpy array
angle = numpy.max(im_np)
# print im_np.shape
im = Image.new('L', (im_np.shape[0], im_np.shape[1]), (0))
draw = ImageDraw.Draw(im)
draw.line([(0,im_np.shape[0]/2), (im_np.shape[0],im_np.shape[0]/2)], fill=255)
im = im.rotate(angle)
img_np2 = numpy.asarray(im)
# print img_np2
return img_np2
def findDomAngle(im_np):
mask = numpy.zeros((180,2))
for i in range(180):
mask[i][0] = i+1
for i in range(im_np.shape[0]):
for j in range(im_np.shape[0]):
mask[im_np[i][j]-1][1] += 1
max = 0
bestdir = 0
for i in range(180):
if mask[i][1] > max:
bestdir = i + 1
max = mask[i][1]
# print mask
# print max
return bestdir
def blkdir(angle_mat):
x = angle_mat.shape[0]
y = angle_mat.shape[1]
# print angle_mat
domAngle = findDomAngle(angle_mat)
# print domAngle
blkAngle = angle_mat
blkAngle.setflags(write=True)
for i in range(x):
for j in range(y):
blkAngle[i][j] = domAngle
return blkAngle
I am applying another function to process the image block by block, but this method has proven to work so I don't find it relevant to include.