Python split image into multiple pieces by horizontal dashed lines - python

I have a bunch of image like this one:
Where the yellow box are contents of different profiles (text), where each section is divided by the dashed lines (no the straight lines). So what I need is to split the image into multiple single images by the dashed lines. So far I have tried a lot of python and cv2 examples with the Hough Line Transform but none of my attempts works in the detection.

Following #efirvida's comment, here's a very basic approach on how to do it.
What it does is simply checking whether each line of pixels in the given picture is equal in value to the first line containing a dashed line, and then crop the picture to split it into multiple pictures...
# import image/array manipulation packages
import cv2
import numpy as np
# read image with OpenCV 2
img = cv2.imread("path/to/file/z4Xje.jpg")
# identify one line of pixels that has dashes
dashes = img[761,:,:]
# check where to split the picture and store that information
splits = [0]
for i in range(img.shape[0]):
# np.allclose allows you to have small differences between dashed lines
if np.allclose(img[i,:,:], dashes):
splits.append(i)
# add last split (height of picture)
splits.append(img.shape[0])
# write each cropped picture to your desired directory
for j in range(len(splits)-1):
new_img = img[splits[j]:splits[j+1],:]
cv2.imwrite("/path/to/export/"+str(j)+".jpg", new_img)
It quite certainly isn't a perfect solution but I hope it gives you clues on how to improve your current algorithm!
It gave me these pictures for the one you provided:
first split
second split
third split

Related

Remove overlapped line over text with opencv

I'm processing images that have a line across the 4 letters. After some processing, i have get this result:
The only thing I can't get to do is remove that black line, so it can be more clear to be recognized with some OCR library. The final image should look like this (not losing quality of text):
I have tried to dilate the image, to try to fill the gaps, but I lose quality:
import cv2
from google.colab.patches import cv2_imshow
import numpy as np
image = cv2.imread("image.png", 0)
cv2_imshow(imagen2)
kernel = np.ones((0,0),np.uint8)
dilation2 = cv2.dilate(imagen2,kernel,iterations = 1) # to remove blackline noise
cv2_imshow(dilation2)
After that, I have tried to erode the image, but this doesn't work well, and I lose more quality:
kernel2 = np.ones((2,2),np.uint8)
closing = cv2.morphologyEx(dilation2, cv2.MORPH_CLOSE, kernel2)
cv2_imshow(closing)
Without knowing the allowed character shapes, this is simply an impossible task. Because from an image processing point of view, nothing qualitatively distinguishes a character and the same character with a line across. So any "blind" processing that removes thin lines will as well destroy thin lines that can legitimately appear in the text, such as the space between characters, and is likely to worsen the problem.

Expanding a contour in python cv2

Using cv2, I am able to find the contours of text in an image. I would like to remove said text and replace it with the average pixel of the surrounding area.
However, the contours are just a bit smaller than I would like, resulting in a blurred edge where one can barely tell what the original text was:
I once chanced upon a cv2 tutorial with a stylized "j" as the sample image. It showed how to "expand" a contour in a manner similar to adding a positive sample next to every pre-existing positive sample in a mask.
If such a method does not already exist in cv2, how may I do this manually?
The function I sought was dilation, as detailed here:
https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.html
import cv2
import numpy as np
img = cv2.imread('j.png',0)
kernel = np.ones((5,5),np.uint8)
dilation = cv2.dilate(img,kernel,iterations = 1)

How to separate each white blob from my png images?

I am given a png image which is strictly two colours: Black and White. More specifically it has a black background and some white marks (we call blobs). Each image has about 30 to 50 such blobs.
Our task is to generate those 30 to 50 sperate images from our given image, with each having one blob .
For example, we have a given image:
We need to convert them into:
And so on with all the blobs. Please guide me on how to do it, I am comfortable with all standard image processing libraries in python.
I think you are looking for scipy.ndimage.measurements.label:
from scipy.ndimage.measurements import label
lb = label(my_bw_image)
msks = []
for li in xrange(1, lb.max()+1):
msks.append(lb==li)
You should have all your masks in msks list.

OpenCV cv2.rectangle output binary image

I have been trying to draw rectangle on a black image, uscv2.rectangle.Here is my code : (It is just a sample, in actual code there is a loop i.e values x2,y2,w2,h2 changes in a loop)
heir = np.zeros((np.shape(image1)[0],np.shape(image1)[1]),np.uint8);
cv2.rectangle(heir,(x2,y2),(x2+w2,y2+h2),(255,255,0),5)
cv2.imshow("img",heir);
cv2.waitKey()
It is giving the following output:
Why the image is like that? Why the boundaries are not just a line a width 5.
I have tried, but I am not able to figure it out.
Can't post this in a comment, but it's a negative answer: the same operations work for me on Windows/python 2.7.8/opencv3.1
import numpy as np
import cv2
heir = np.zeros((100,200),np.uint8);
x2=10
y2=20
w2=30
h2=40
cv2.rectangle(heir,(x2,y2),(x2+w2,y2+h2),(255,255,0),5)
cv2.imshow("img",heir);
cv2.waitKey()
Because you are loading the image to be tagged (draw rectangles) in grayscale, thats why when you are adding rectangles/bounding boxes the colors are being converted to grayscale.
To fix the issue, open image in "color" format. Since, you didn't included that part of code, here is the proposed solution:
tag_img = cv2.imread(MYIMAGE,1)
Pay attention to the second parameter here, which is "1" and means load image as color. Read more about reading images here: https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_gui/py_image_display/py_image_display.html

Python PIL: best scaling method that preserves lines

I have a 2D drawing with a black background and white lines (exported from Autocad) and I want to create a thumbnail preserving lines, using Python PIL library.
But what I obtain using the 'thumbnail' method is just a black picture scattered with white dots.
Note that if I put the image into an IMG tag with fixed width, I obtain exactly what I want (but the image is entirely loaded).
After your comments, here is my sample code:
from PIL import Image
fn = 'filename.gif'
im = Image(fn)
im.convert('RGB')
im.thumbnail((300, 300), Image.ANTIALIAS)
im.save('newfilename.png', 'PNG')
How can I do?
The default resizing method used by thumbnail is NEAREST, which is a really bad choice. If you're resizing to 1/5 of the original size for example, it will output one pixel and throw out the next 4 - a one-pixel wide line has only a 1 out of 5 chance of showing up at all in the result!
The surprising thing is that BILINEAR and BICUBIC aren't much better. They take a formula and apply it to the 2 or 3 closest pixels to the source point, but there's still lots of pixels they don't look at, and the formula will deemphasize the line anyway.
The best choice is ANTIALIAS, which appears to take all of the original image into consideration without throwing away any pixels. The lines will become dimmer but they won't disappear entirely; you can do an extra step to improve the contrast if necessary.
Note that all of these methods will fall back to NEAREST if you're working with a paletted image, i.e. im.mode == 'P'. You must always convert to 'RGB'.
from PIL import Image
im = Image.open(fn)
im = im.convert('RGB')
im.thumbnail(size, Image.ANTIALIAS)
Here's an example taken from the electronics.stackexchange site https://electronics.stackexchange.com/questions/5412/easiest-and-best-poe-ethernet-chip-micro-design-for-diy-interface-with-custom-ard/5418#5418
Using the default NEAREST algorithm, which I assume is similar to the results you had:
Using the ANTIALIAS algorithm:
By default, im.resize uses the NEAREST filter, which is going to do what you're seeing -- lose information unless it happens to fall on an appropriately moduloed pixel.
Instead call
im.resize(size, Image.BILINEAR)
This should preserve your lines. If not, try Image.BICUBIC or Image.ANTIALIAS. Any of those should work better than NEAREST.

Categories

Resources