0
$\begingroup$

Suppose we have a grayscale image that contains vertical lines. Now suppose that not all vertical lines are the same, some of them have different thickness.

Question is, is there a way, in MATLAB or other programming language, to filter the vertical lines by thickness? In other words, based on the user selected thickness, only thin vertical lines are removed, while all other thick vertical lines are kept intact? or all thick vertical lines removed, all other thin vertical lines intact?

I tried experimenting with MATLAB with the morphological operators, but nothing seems to really work, perhaps I am using the wrong method.

edit: I am thinking about one possible way to solve this, but not in code, just as an idea. Every vertical line has 2 vertical edges. For every pair of 2 edges (1 line), calculate distance between two edges. Then, based on user threshold, remove or keep corresponding lines based on these calculated distances.

edit2: here is sample image: sample image How to remove only 3 thin lines and keep 2 thick lines OR how to remove 2 thick lines and keep 3 thin lines? That is what I have to accomplish.

edit3: what I mean by remove is in this context interpolate them with the background (average value of left and right close pixels).

$\endgroup$
10
  • $\begingroup$ Can you please post a sample image? $\endgroup$
    – A_A
    Commented May 19, 2018 at 17:52
  • $\begingroup$ It can be really any image, you can even make your own, something like this: mathworks.com/help/images/… , I was thinking about using Radon/Hough maybe, but not sure how to work with those. The point of my question is just in general, not about a specific image out there. Thank you $\endgroup$
    – Dan
    Commented May 19, 2018 at 19:36
  • $\begingroup$ Thank you, are the bars repetitive across the image? Is there content within the bars that you would be interested in preserving or are you simply interested in removing something like a banding artifact? $\endgroup$
    – A_A
    Commented May 19, 2018 at 20:02
  • $\begingroup$ I am not worried about overlapping bars, just separate bars of different thickness (length). They can repeat, but doesn't have to. The goal is to find a filtering method of only removing vertical bars based on some threshold (thickness length), so that you keep bars above threshold and remove below, or vice-versa. $\endgroup$
    – Dan
    Commented May 19, 2018 at 20:52
  • $\begingroup$ Dan, If you link to a sample image we could assist more easily. I have an idea which is based on some assumptions. I just need to see a sample to make sure the assumptions make sense. $\endgroup$
    – Royi
    Commented May 19, 2018 at 22:38

1 Answer 1

0
$\begingroup$

Here is some Python code that does mostly what you want. You need to add the thick/thin line selection logic. You'll probably want to tweak it some more too. There seem to be some artifacts when it is turned back into a .jpg.

from PIL    import Image

import numpy as np

#============================================================
def main():

#---- Load the Image

        theImage = Image.open( "test.jpg")

        thePixels = theImage.load()

        theRangeMin = 0
        theRangeMax = 7

#---- Get the Size

        theSize = theImage.size

        theWidth  = theSize[0]
        theHeight = theSize[1]

        print theWidth, theHeight

#---- Scan some Rows

        theSum = np.zeros( theWidth )
        theScanCount = 0

        for n in range( 100, theHeight, 100 ):
            print n
            theScanCount += 1

            for m in range( theWidth ):
                theShade = thePixels[m,n]
                theSum[m] += theShade[0] + theShade[1] + theShade[2]

#---- Calculate Derivatives

        theFirst  = np.zeros( theWidth )
        theSecond = np.zeros( theWidth )
        theSum /= ( 3.0 * theScanCount )

        for m in range( 1, theWidth-1 ):
            theFirst[m]  = ( theSum[m+1] - theSum[m-1] ) * 0.5
            theSecond[m] = theSum[m+1] - 2.0 * theSum[m] + theSum[m-1]
            print m, theSum[m], theSecond[m], theFirst[m]


#---- Find Vertical Lines

        theThreshold = 10

        theLastFirst = 0

        theLines = []

        m = 1
        while m < theWidth-1:
            if theSum[m] < theThreshold:
                while m < theWidth-1:
                    if theSum[m] > theThreshold and theFirst[m] < theThreshold:
                        break
                    m += 1

                print theLastFirst, m
                theRange = m - theLastFirst
                theRate = 1.0 / float( theRange )
                if theRangeMin <= theRange and theRange <= theRangeMax :
                    theLines.append( [ theLastFirst, m, theRange, theRate ] )

            elif abs( theFirst[m] ) < theThreshold : theLastFirst = m

            m += 1

#---- Hide the Lines

        theLineCount = len( theLines )

        for n in range( theHeight ):
            for p in range( theLineCount ):
                theLine = theLines[p]

                theSpot = theLine[0]
                theFirstShade = thePixels[theSpot,n]
                theLastShade  = thePixels[theLine[1],n]
                theRange = theLine[2]
                theRate  = theLine[3]
                theFirstVal = ( theFirstShade[0] + theFirstShade[1] + theFirstShade[2] ) / 3.0 
                theLastVal  = ( theLastShade[0]  + theLastShade[1]  + theLastShade[2] ) / 3.0
                theSlope = ( theLastVal - theFirstVal ) * theRate

                if n == 100: print theSpot, theFirstVal, theLastVal

                for r in range( 1, theRange ):
                    theVal = theFirstVal + r * theSlope
                    theGrey = int( theVal ) & 0xFF
                    theShade = ( theGrey << 16 ) + ( theGrey << 8 ) + theGrey
                    thePixels[theSpot+r,n] = theShade
                    if n == 100: print "     ", theVal

#---- Write the Image to a File

        theImage.save( "out.jpg" )

#============================================================
main()


Followup:

Here is the debug output at the first thin line:

194 119.857142857 8.85714285714 -1.14285714286
195 123.142857143 -3.71428571429 1.42857142857
196 122.714285714 -64.7142857143 -32.7857142857
197 57.5714285714 13.8095238095 -58.2380952381
198 6.2380952381 88.0 -7.33333333333
199 42.9047619048 42.7142857143 58.0238095238
200 122.285714286 -79.2380952381 39.7619047619
201 122.428571429 0.428571428571 0.357142857143
202 123.0 -0.142857142857 0.5
203 123.428571429 0.0 0.428571428571
204 123.857142857 0.142857142857 0.5
205 124.428571429 -0.285714285714 0.428571428571
206 124.714285714 1.42108547152e-14 0.285714285714
$\endgroup$
13
  • $\begingroup$ Interesting, I will try to convert this into MATLAB code. Can you please just explain the method in words. The strategy. Is this purely your code or you took from somewhere? Thank you! $\endgroup$
    – Dan
    Commented May 21, 2018 at 22:55
  • $\begingroup$ @Dan, This is freshly produced custom code in response to your question. I added some of the output so you can see how the numbers work. Installing Python might be easier than converting to MATLAB. I ended up not using the "second derivative" calculation, so you can slice that out. Basically the code looks for a low area (notice because of the jpg compressing, the stripes aren't that stark), then looks in each direction for "level" values. The comments and the variables names should allow you to follow the strategy. $\endgroup$ Commented May 22, 2018 at 1:54
  • $\begingroup$ I already tried it in Python, works nicely to hide the lines, very awesome job! Now only thing is from here, to allow hiding lines based on thickness level. Thank you $\endgroup$
    – Dan
    Commented May 22, 2018 at 2:30
  • $\begingroup$ @Dan,Your image wasn't exactly greyscale, as in R=G=B. You may get slightly better results if you ramp the R, G, and B values separately when removing the line. I did the quick and dirtly average since it was close to greyscale. If you like my answer, then you should accept it, maybe even upvote it. $\endgroup$ Commented May 22, 2018 at 18:37
  • $\begingroup$ OK, I accepted your answer, best for now :) Even tho the main problem is not solved yet. $\endgroup$
    – Dan
    Commented May 22, 2018 at 19:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.